zoj3966 Domino Tiling dp

本文探讨了一种特殊的棋盘覆盖问题,其中使用1x2的矩形拼接一个n*m的棋盘,需遵循特定规则以避免四个不同矩形的角汇聚于一点。通过确定性的方法和螺旋式的放置策略,结合动态规划来解决该问题并提供了一种可行的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给你一个n*m的棋盘 你只能用1x2的格子拼接 且不能同时有4个不同格子的角汇聚在同一处。200组左右的输入 输出任意方案。

题解:由于限制条件太强所以最优方法是确定的 首先假设n<m n如果是n偶数则可拼出1*n (n-2)*n (n-1)*n (n+1)*n 的矩形(前面数列数,后面是行数) 假如n是奇数就只能拼出n-1 n+1 列的矩形。 方法是螺旋形的放 然后dp时要讨论每种矩阵开头和结尾列的情况。

#include <bits/stdc++.h>
using namespace std;
#define orz printf("orz\n");
#define pf printf
#define ss system("pause");
#define pii pair<int,int>
#define mp make_pair
#define sz size()
#define pb push_back
#define ft first
#define sd second
int vis[110][110];
int flag,n,m,ff,cnt;
int a[10];
int dx[2][4]={1,0,-1,0,0,1,0,-1};
int dy[2][4]={0,1,0,-1,1,0,-1,0};
int lim1,lim2;
void dfs(int x,int y,int kind,int dir,int f)
{
    vis[x][y]=cnt;
    int xx;int yy;

    for(int i=0;i<4;i++)
    {
        xx=x+dx[kind][dir];
        yy=y+dy[kind][dir];
        if(xx<1||xx>n||yy<lim1||yy>lim2||vis[xx][yy])
        {
            dir=(dir+1)%4;
        }
        else
        {
            break;
        }
    }
    if(xx<1||xx>n||yy<lim1||yy>lim2)
    {
            return;
    }
    if(vis[xx][yy])
    {
            return;
    }
    if(f==1)
    {
        dfs(xx,yy,kind,dir,f^1);
    }
    else
    {
        cnt++;
        dfs(xx,yy,kind,dir,f^1);
    }
}
int dp[210][2];
vector<pii>ed[2],st[2];
int labst[10],labed[10];
void solve()
{
    memset(dp,-1,sizeof(dp));
    dp[0][0]=dp[0][1]=0;

    for(int i=0;i<2;i++) ed[i].clear();
    for(int i=0;i<2;i++) st[i].clear();
    if(n%2==0)
    {
        ed[0].pb( mp(1 ,1  ) ); labed[1]=0;
        ed[0].pb( mp(2 ,n-1) ); labed[2]=0;
        ed[0].pb( mp(5 ,n  ) ); labed[5]=0;
        ed[0].pb( mp(6 ,n+1) ); labed[6]=0;


        ed[1].pb( mp(3 ,n-1) ); labed[3]=1;
        ed[1].pb( mp(4 ,n  ) ); labed[4]=1;
        ed[1].pb( mp(7 ,n+1) ); labed[7]=1;
        if(n>2)
        {
            ed[1].pb( mp(8 ,n-2));
            labed[8]=1;
            st[1].pb( mp(8 ,n-2));
            labst[8]=1;
        }
        st[0].pb( mp(1 ,1  ) ); labst[1]=0;
        st[0].pb( mp(3 ,n-1) ); labst[3]=0;
        st[0].pb( mp(5 ,n  ) ); labst[5]=0;
        st[0].pb( mp(7 ,n+1) ); labst[7]=0;

        st[1].pb( mp(2 ,n-1) ); labst[2]=1;
        st[1].pb( mp(4 ,n  ) ); labst[4]=1;
        st[1].pb( mp(6 ,n+1) ); labst[6]=1;
    }
    else
    {
        ed[1].pb( mp(1 ,n-1) ); labed[1]=1;
        ed[1].pb( mp(3 ,n+1) ); labed[3]=1;
        ed[0].pb( mp(2 ,n-1) ); labed[2]=0;
        ed[0].pb( mp(4 ,n+1) ); labed[4]=0;

        st[1].pb( mp(1 ,n-1) ); labst[1]=1;
        st[1].pb( mp(3 ,n+1) ); labst[3]=1;
        st[0].pb( mp(2 ,n-1) ); labst[2]=0;
        st[0].pb( mp(4 ,n+1) ); labst[4]=0;
    }

    int t1,len;
    for(int i=0;i<m;i++)
    {
        if(dp[i][1]!=-1)
        {
            for(int j=0;j<st[0].sz;j++)
            {
                if(i+st[0][j].sd>m) continue;
                t1=st[0][j].ft;
                len=st[0][j].sd;
                dp[i+len][labed[t1]]=(i<<1)|1;
            }
        }
        if(dp[i][0]!=-1)
        {
            for(int j=0;j<st[1].sz;j++)
            {
                if(i+st[1][j].sd>m) continue;
                t1=st[1][j].ft;
                len=st[1][j].sd;
                dp[i+len][labed[t1]]=(i<<1)|0;
            }
        }
    }
}
void path(int y,int kind)
{
    //printf("path: %d %d\n",y,kind);
    if(y<1) return;
    cnt++;
    int last=dp[y][kind]>>1;
    int situ=dp[y][kind]&1;
    lim1=last+1;lim2=y;
    dfs(1,last+1,situ^1,0,1);
    path(last,situ);
}
void toput()
{
    if(ff)
    {
        //printf("*******************\n");
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<n;j++)
            {
                printf("%d ",vis[j][i]);
            }
            printf("%d\n",vis[n][i]);
        }
        //pf("*******************\n");
        return;
    }
    //pf("*******************\n");
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<m;j++)
        {
            printf("%d ",vis[i][j]);
            //printf("%d ",vis[i][j]);
        }
        //printf("%d\n",vis[i][m]);
        printf("%d\n",vis[i][m]);
    }
    //pf("*******************\n");
}
void print()
{
    if(dp[m][1]!=-1)
    {
        path(m,1);
    }
    else
    {
        path(m,0);
    }
    toput();
}
int main()
{
    int cas;
    //freopen("out.txt","w",stdout);
    scanf("%d",&cas);
    //cas=20;
    while(cas--)
    //for(int i=1;i<=1;i++)
    {

        cnt=0;
        flag=0;
        memset(vis,0,sizeof (vis));
        scanf("%d%d",&n,&m);
        //n=24;m=26;
        ff=0;
        if(n>m) swap(n,m),ff=1;
        if((n*m) &1)
        {
            printf("Impossible!\n");
            continue;
        }
        if(n==1)
        {
            lim1=1;lim2=m;
            cnt++;
            dfs(1,1,1,0,1);
            toput();
            continue;
        }
        solve();
        if(dp[m][1]==-1 &&dp[m][0]==-1)
        {
            printf("Impossible!\n");
        }
        else  print();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值