【TJOI2014】拼图(puzzle)

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

4
2 3
111
101
4 2
01
01
11
01
2 1
1
1
3 2
10
10
11
4
1 4
1111
1 4
1111
1 4
1111
1 4
1111
4
1 4
1111
1 4
1111
1 4
1111
2 3
111
001

Sample Output

Yes, only one!
1112
1412
3422
3442
Yes, many!
No solution

Data Constraint

30%的数据,N<5

100%的数据,N<=16

分析

由于每一个piece都不能旋转和反转,所以每一个r ∗c的piece,他只能 有(4−r+1)∗(4−c+1)种摆放的位置。枚举摆放的位置,构建 dancing-link 模型,要求4∗4个方格都被覆盖,并且每一个piece都要用到,所以总共需 要覆盖4∗4 + n列。每一种摆放位置覆盖了他所有的’1’的位置的列以及这 个piece的列。最后搜索到4*4+n列都被覆盖时,就是一个可行解。类似于 数独。

代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int INF=0x1f1f1f1f;
#define N 4
int res[N][N];
int cnt[100];
int sz[100];
int C,R;
struct Node
{
    Node *u,*d,*l,*r;
    int n;
}*nd,nodes[50000],*row[1000],*col[100],*stack[5000];

int top;

Node* newNode(int p)
{
    nd->u=nd->d=nd->r=nd->l=nd;
    nd->n=p;
    if(p>=0)cnt[p]++;
    return nd++;
}

void init(int c)
{
    top=0;
    C=c;
    R=0;
    nd=nodes;
    memset(cnt,0,sizeof(cnt));
    for(int i=0;i<c;i++)
    {
        col[i]=newNode(-1);
    }
}

void link(Node *a,Node *b,Node *c)
{
    a->r=b->r;
    a->l=b;
    b->r->l=a;
    b->r=a;
    a->d=c->d;
    a->u=c;
    c->d->u=a;
    c->d=a;
}

void addRow()
{
    row[R]=newNode(-1);
    R++;
}

void readd(Node *a)
{
    a->l->r=a;
    a->r->l=a;
    a->u->d=a;
    a->d->u=a;
    cnt[a->n]++;
}

void del(Node *a)
{
    a->l->r=a->r;
    a->r->l=a->l;
    a->u->d=a->d;
    a->d->u=a->u;
    cnt[a->n]--;
    stack[top++]=a;
}

bool delRow(Node *a)
{
    while(true)
    {
        Node *tt=a->r;
        if(tt->n==-1)tt=tt->r;
        del(tt);
        if(cnt[tt->n]==0)return true;
        if(tt==a)return false;
    }
}

bool delCol(Node *a)
{
    while(true)
    {
        Node *tt=a->d;
        if(tt->n==-1)tt=tt->d;
        if(tt==a)
        {
            del(tt);
            return false;
        }
        if(delRow(tt))return true;
    }
}

int CC;
int ans[N][N];

void dfs(int step)
{
    if(CC>1)return;
    if(step==C)
    {
        memcpy(ans,res,sizeof(res));
        CC++;
        return;
    }
    int m=INF;
    int k;
    for(int i=0;i<C;i++)
    {
        if(cnt[i]>0&&cnt[i]<m)
        {
            m=cnt[i];
            k=i;
        }
    }
    if(m==INF)
        return;
    for(Node *arr=col[k]->d;arr!=col[k];arr=arr->d)
    {
        int tmp=top;
        int num;
        vector<int>pos;
        while(true)
        {
            Node *tt=arr->r;
            if(tt->n==-1)tt=tt->r;
            if(tt->n<N*N)pos.push_back(tt->n);
            else num=tt->n-N*N+1;
            if(delCol(tt))break;
            if(tt==arr)
            {
                for(int ii=0;ii<pos.size();ii++)
                    res[pos[ii]/N][pos[ii]%N]=num;
                dfs(step+sz[num]);
                break;
            }
        }
        while(top>tmp)
        {
            top--;
            readd(stack[top]);
        }
    }
}

char ch[N][N];

int Hash(int x,int y)
{
    return x*N+y;
}

int main()
{
    freopen("puzzle.in", "r", stdin);
    freopen("puzzle.out", "w", stdout);
    int n;

    while(scanf("%d",&n) != EOF)
    {
        init(16+n);
        for(int id=1;id<=n;id++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            for(int i=0;i<a;i++)
                scanf("%s",ch[i]);
            for(int sx=0;sx+a<=N;sx++)
                for(int sy=0;sy+b<=N;sy++)
                {
                    addRow();
                    sz[id]=1;
                    for(int i=0;i<a;i++)
                        for(int j=0;j<b;j++)
                        {
                            if(ch[i][j]=='1')
                            {
                                link(newNode(Hash(i+sx,j+sy)),row[R-1],col[Hash(i+sx,j+sy)]);
                                sz[id]++;
                            }
                        }
                    link(newNode(N*N-1+id),row[R-1],col[N*N-1+id]);
                }
        }
        CC=0;
        dfs(0);
        if(CC==0)
            printf("No solution\n");
        else if(CC>1)
        {
            printf("Yes, many!\n");
        }
        else 
        {
            printf("Yes, only one!\n");
            for(int i=0;i<N;i++)
            {
                for(int j=0;j<N;j++)
                    printf("%d",ans[i][j]);
                printf("\n");
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值