首页 > 代码库 > ZOJ 3209 Dancing Links

ZOJ 3209 Dancing Links

思路:这题挺好的,本来模板不是自己敲的嘛,理解了Dancing Links后是找了一个模板的,然后正好这题让自己加深理解了,也知道在实际中怎么建矩阵求解了。

把n*m的矩阵看成n*m个格子,像那个数独一样,作为n*m列;每一个矩形一行。

行列都建好矩阵后,就可以用舞蹈链求解了。

问题即转化为从这些行中选择最少的一部分使每一列被覆盖且仅覆盖一次。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 1000005
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int head,sz;
int U[maxn],D[maxn],L[maxn],R[maxn];//上下左右链表指针
int H[maxn],ROW[maxn],C[maxn],S[maxn],O[maxn];
void remove(int c)
{
    L[R[c]]=L[c];
    R[L[c]]=R[c];
    for(int i=D[c]; i!=c; i=D[i])
        for(int j=R[i]; j!=i; j=R[j])
        {
            U[D[j]]=U[j];
            D[U[j]]=D[j];
            --S[C[j]];
        }
}
void resume(int c)
{
    for(int i=U[c]; i!=c; i=U[i])
    {
        for(int j=L[i]; j!=i; j=L[j])
        {
            ++S[C[j]];
            U[D[j]]=j;
            D[U[j]]=j;
        }
    }
    L[R[c]]=c;
    R[L[c]]=c;
}
void init(int m)//m是列
{
    head=0;//头指针为0
    for(int i=0; i<=m; i++)
    {
        U[i]=i;
        D[i]=i;//建立双向十字链表
        L[i]=i-1;
        R[i]=i+1;
        S[i]=0;
    }
    R[m]=0;
    L[0]=m;
    S[0]=INF+1;
    sz=m+1;
    memset(H,0,sizeof(H));
}
void insert(int i, int j)
{
    if(H[i])
    {
        L[sz] = L[H[i]];
        R[sz] = H[i];
        L[R[sz]] = sz;
        R[L[sz]] = sz;
    }
    else
    {
        L[sz] = sz;
        R[sz] = sz;
        H[i] = sz;
    }
    U[sz] = U[j];
    D[sz] = j;
    U[D[sz]] = sz;
    D[U[sz]] = sz;
    C[sz] = j;
    ROW[sz] = i;
    ++S[j];
    ++sz;
}
int ans;
void dfs(int k)
{
    if(R[head]==head)
    {
        if(ans>k) ans=k;
        return;
    }
    int s=INF,c;
    for (int t=R[head]; t!=head; t=R[t])
        if (S[t]<s) s=S[t],c=t;
    remove(c);
    for(int i=D[c]; i!=c; i=D[i])
    {
        O[k]=ROW[i];
        for(int j=R[i]; j!=i; j=R[j])
            remove(C[j]);
        dfs(k+1);
        for(int j=L[i]; j!=i; j=L[j])
            resume(C[j]);
    }
    resume(c);
}
int main()
{
    //freopen("1.txt","r",stdin);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m,p,i,j,k,x1,y1,x2,y2;
        scanf("%d%d%d",&n,&m,&p);
        init(n*m);
        for(i=1;i<=p;i++)
        {
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            for(j=x1;j<x2;j++)
                for(k=y1+1;k<=y2;k++)
                    insert(i,j*m+k);
        }
        ans=INF;
        dfs(0);
        printf("%d\n",ans==INF?-1:ans);
    }
    return 0;
}


ZOJ 3209 Dancing Links