Dancing Links 重复覆盖问题~

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3498

这两天学习了Dancing Links  ,它主要对搜索的优化,尤其对于矩阵, 进行深搜的时候,随着层数的加深,矩阵会越来越稀疏,

如果还是用一般的遍历的话, 时间还是没变,还是遍历整个矩阵, 因为矩阵已经变稀疏了,这样做很显然的浪费时间,

这里用到Dancing Links,相信它优美的舞步,一定能打动你的。。

Dancing Links用到一个十字链表, 众所周知 链表对于插入和删除的处理 时间复杂度都是O(1), 这里就要用到链表的这一特性,

对矩阵的某一行或列进行删除的时候 ,先标记,之后把其删除, 等到搜索过后,再把其恢复,时间效率大大的提高。。

Dancing 一般用来解决精确覆盖的问题, 像本题属于 重复覆盖的问题, Dancing Links并不能优化多少,但是这里加一个评估函数,

就在很大的程度上提高了它的效率。、

题目大意:深渊领主有一个技能,溅射(分列攻击),当它把一个单位杀死的时候与该单位 直接 相连的所有单位都要被杀死,

给出n个单位之间的关系,问把这n个单位全部杀死,至少需要攻击多少次。

思路:n个单位排成一排,与该单位相连的单位,以及它自身,位于这一列, 即是Dancing links里面的0-1矩阵。

h函数是这样写的:

当前这种状态至少还需要攻击多少次才能把所有单位消灭。任选没有被标记的一个单位,然后把该列中每一个元素所对应的行,

该行中每一个元素所对应的单位都标记下来。 因为一般我们都只能选取 该列中的一个元素,然后进行处理, 这里把该列中所有的元素都选取出来

,然后进行处理,所需要的次数肯定要比一般情况下的少。。  

 我感觉吧,这个评估函数写的不够风骚,虽然我还没有想到更好的办法。 虽然他能把这题A掉,但是我感觉应该还会有更好的优化!

这道题应该算是一个比较裸的Dancing Links了。。

code:

View Code
  1 # include<stdio.h>
2 # include<string.h>
3 # define N 60
4 # define V N*N
5 int L[V],R[V];//记录左右方向的双向链表
  6 int U[V],D[V];//记录上下方向的双向链表
7 int C[V];//指向其列指针头的地址
8 int H[N];//行指针头
9 int S[N];//记录列链表中节点的总数
10 int size,n,m,ak;
11 int mark[N][N],visit[N];
12 void Link(int r,int c)
13 {
14 S[c]++;C[size]=c;
15 U[size]=U[c];D[U[c]]=size;
16 D[size]=c;U[c]=size;
17 if(H[r]==-1) H[r]=L[size]=R[size]=size;
18 else
19 {
20 L[size]=L[H[r]];R[L[H[r]]]=size;
21 R[size]=H[r];L[H[r]]=size;
22 }
23 size++;
24 }
25 void remove(int Size)
26 {
27 int j;
28 for(j=D[Size];j!=Size;j=D[j])
29 L[R[j]]=L[j],R[L[j]]=R[j];
30 }
31 void resume(int Size)
32 {
33 int j;
34 for(j=D[Size];j!=Size;j=D[j])
35 L[R[j]]=R[L[j]]=j;
36 }
37 int h()
38 {
39 int count=0,i,j,k;
40 memset(visit,0,sizeof(visit));
41 for(i=R[0];i;i=R[i])
42 {
43 if(visit[i]) continue;
44 count++;
45 for(j=D[i];j!=i;j=D[j])
46 {
47 for(k=R[j];k!=j;k=R[k])
48 visit[C[k]]=1;
49 }
50 }
51 return count;
52 }
53 void Dance(int k)
54 {
55 int i,j,min,c;
56 if(k+h()>=ak) return;
57 if(!R[0])
58 {
59 if(k<ak) ak=k;
60 return;
61 }
62 for(min=N,i=R[0];i;i=R[i])
63 if(min>S[i]) min=S[i],c=i;
64 for(i=D[c];i!=c;i=D[i])
65 {
66 remove(i);
67 for(j=R[i];j!=i;j=R[j])
68 remove(j);
69 Dance(k+1);
70 for(j=R[i];j!=i;j=R[j])
71 resume(j);
72 resume(i);
73 }
74 }
75 int main()
76 {
77 int i,j,a,b;
78 while(scanf("%d%d",&n,&m)!=EOF)
79 {
80 for(i=0;i<=n;i++)
81 {
82 S[i]=0;
83 U[i]=D[i]=i;
84 L[i+1]=i;R[i]=i+1;
85 }R[n]=0;
86 size=n+1;
87 memset(mark,0,sizeof(mark));
88 memset(H,-1,sizeof(H));
89 while(m--)
90 {
91 scanf("%d%d",&a,&b);
92 mark[a][b]=mark[b][a]=1;
93 }
94 for(i=1;i<=n;i++)
95 {
96 for(j=1;j<=n;j++)
97 {
98 if(mark[i][j] || i==j) Link(i,j);
99 }
100 }
101 ak=N;
102 Dance(0);
103 printf("%d\n",ak);
104 }
105 return 0;
106 }
posted on 2011-08-07 08:55  奋斗青春  阅读(569)  评论(0编辑  收藏  举报