whosyourdaddy
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1028 Accepted Submission(s): 508
这两天学习了Dancing Links ,它主要对搜索的优化,尤其对于矩阵, 进行深搜的时候,随着层数的加深,矩阵会越来越稀疏,
如果还是用一般的遍历的话, 时间还是没变,还是遍历整个矩阵, 因为矩阵已经变稀疏了,这样做很显然的浪费时间,
这里用到Dancing Links,相信它优美的舞步,一定能打动你的。。
Dancing Links用到一个十字链表, 众所周知 链表对于插入和删除的处理 时间复杂度都是O(1), 这里就要用到链表的这一特性,
对矩阵的某一行或列进行删除的时候 ,先标记,之后把其删除, 等到搜索过后,再把其恢复,时间效率大大的提高。。
Dancing 一般用来解决精确覆盖的问题, 像本题属于 重复覆盖的问题, Dancing Links并不能优化多少,但是这里加一个评估函数,
就在很大的程度上提高了它的效率。、
题目大意:深渊领主有一个技能,溅射(分列攻击),当它把一个单位杀死的时候与该单位 直接 相连的所有单位都要被杀死,
给出n个单位之间的关系,问把这n个单位全部杀死,至少需要攻击多少次。
思路:n个单位排成一排,与该单位相连的单位,以及它自身,位于这一列, 即是Dancing links里面的0-1矩阵。
h函数是这样写的:
当前这种状态至少还需要攻击多少次才能把所有单位消灭。任选没有被标记的一个单位,然后把该列中每一个元素所对应的行,
该行中每一个元素所对应的单位都标记下来。 因为一般我们都只能选取 该列中的一个元素,然后进行处理, 这里把该列中所有的元素都选取出来
,然后进行处理,所需要的次数肯定要比一般情况下的少。。
我感觉吧,这个评估函数写的不够风骚,虽然我还没有想到更好的办法。 虽然他能把这题A掉,但是我感觉应该还会有更好的优化!
这道题应该算是一个比较裸的Dancing Links了。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 5 const int N=60; 6 const int V=N*N; 7 8 int L[V],R[V]; //记录左右方向的双向链表 9 int U[V],D[V]; //记录上下方向的双向链表 10 int C[V]; //指向其列指针头的地址 11 int H[N]; //行指针头 12 int S[N]; //记录列链表中节点的总数 13 int size,n,m,ak; 14 int mark[N][N],vis[N]; 15 16 void Link(int r,int c){ 17 S[c]++;C[size]=c; 18 U[size]=U[c]; D[U[c]]=size; 19 D[size]=c; U[c]=size; 20 if(H[r]==-1) 21 H[r]=L[size]=R[size]=size; 22 else{ 23 L[size]=L[H[r]]; R[L[H[r]]]=size; 24 R[size]=H[r]; L[H[r]]=size; 25 } 26 size++; 27 } 28 29 void remove(int Size){ 30 int j; 31 for(j=D[Size];j!=Size;j=D[j]) 32 L[R[j]]=L[j],R[L[j]]=R[j]; 33 } 34 35 void resume(int Size){ 36 int j; 37 for(j=D[Size];j!=Size;j=D[j]) 38 L[R[j]]=R[L[j]]=j; 39 } 40 41 int h(){ 42 int count=0; 43 int i,j,k; 44 memset(vis,0,sizeof(vis)); 45 for(i=R[0];i;i=R[i]){ 46 if(vis[i]) 47 continue; 48 count++; 49 for(j=D[i];j!=i;j=D[j]) 50 for(k=R[j];k!=j;k=R[k]) 51 vis[C[k]]=1; 52 } 53 return count; 54 } 55 56 void Dance(int k){ 57 if(k+h()>=ak) 58 return ; 59 if(!R[0]){ 60 if(k<ak) 61 ak=k; 62 return ; 63 } 64 int min=N; 65 int i,j,c; 66 for(i=R[0];i;i=R[i]) 67 if(min>S[i]) 68 min=S[i],c=i; 69 for(i=D[c];i!=c;i=D[i]){ 70 remove(i); 71 for(j=R[i];j!=i;j=R[j]) 72 remove(j); 73 Dance(k+1); 74 for(j=R[i];j!=i;j=R[j]) 75 resume(j); 76 resume(i); 77 } 78 } 79 80 int main(){ 81 82 //freopen("input.txt","r",stdin); 83 84 while(~scanf("%d%d",&n,&m)){ 85 int i,j; 86 for(i=0;i<=n;i++){ 87 S[i]=0; 88 U[i]=D[i]=i; 89 L[i+1]=i;R[i]=i+1; 90 } 91 R[n]=0; 92 size=n+1; 93 memset(mark,0,sizeof(mark)); 94 memset(H,-1,sizeof(H)); 95 int a,b; 96 while(m--){ 97 scanf("%d%d",&a,&b); 98 mark[a][b]=mark[b][a]=1; 99 } 100 for(i=1;i<=n;i++) 101 for(j=1;j<=n;j++) 102 if(mark[i][j] || i==j) 103 Link(i,j); 104 ak=N; 105 Dance(0); 106 printf("%d\n",ak); 107 } 108 return 0; 109 }