hdu 3498 Dancing link 重复覆盖

# include<stdio.h>
 # include<string.h>
 # define N 60
 # define V N*N
 int L[V],R[V];//记录左右方向的双向链表
 int U[V],D[V];//记录上下方向的双向链表
 int C[V];//指向其列指针头的地址
 int H[N];//行指针头
 int S[N];//记录列链表中节点的总数
 int size,n,m,ak;
 int mark[N][N],visit[N];
 void Link(int r,int c)
 {
     S[c]++;C[size]=c;
     U[size]=U[c];D[U[c]]=size;
     D[size]=c;U[c]=size;
     if(H[r]==-1) H[r]=L[size]=R[size]=size;
     else
     {
         L[size]=L[H[r]];R[L[H[r]]]=size;
         R[size]=H[r];L[H[r]]=size;
     }
     size++;
 }
 void remove(int Size)
 {
     int j;
     for(j=D[Size];j!=Size;j=D[j])
         L[R[j]]=L[j],R[L[j]]=R[j];
 }
 void resume(int Size)
 {
     int j;
     for(j=D[Size];j!=Size;j=D[j])
         L[R[j]]=R[L[j]]=j;
 }
 int h()
 {
     int count=0,i,j,k;
     memset(visit,0,sizeof(visit));
     for(i=R[0];i;i=R[i])
     {
         if(visit[i]) continue;
         count++;
         for(j=D[i];j!=i;j=D[j])
         {
             for(k=R[j];k!=j;k=R[k])
                 visit[C[k]]=1;
         }
     }
     return count;
 }
 void Dance(int k)
 {
     int i,j,min,c;
     if(k+h()>=ak) return;
     if(!R[0])
     {
         if(k<ak) ak=k;
         return;
     }
     for(min=N,i=R[0];i;i=R[i])
         if(min>S[i]) min=S[i],c=i;
     for(i=D[c];i!=c;i=D[i])
     {
         remove(i);
         for(j=R[i];j!=i;j=R[j])
             remove(j);
         Dance(k+1);
         for(j=R[i];j!=i;j=R[j])
             resume(j);
         resume(i);
     }
 }
 int main()
 {
     int i,j,a,b;
     while(scanf("%d%d",&n,&m)!=EOF)
     {
         for(i=0;i<=n;i++)
         {
             S[i]=0;
             U[i]=D[i]=i;
             L[i+1]=i;R[i]=i+1;
         }R[n]=0;
         size=n+1;
         memset(mark,0,sizeof(mark));    
         memset(H,-1,sizeof(H));
         while(m--)
         {
             scanf("%d%d",&a,&b);
             mark[a][b]=mark[b][a]=1;
         }
         for(i=1;i<=n;i++)
         {
             for(j=1;j<=n;j++)
             {
                 if(mark[i][j] || i==j) Link(i,j);
             }
         }
         ak=N;
         Dance(0);
         printf("%d\n",ak);
     }
     return 0;
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值