HDU 3498 whosyourdaddy

whosyourdaddy

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1028    Accepted Submission(s): 508

Problem Description
sevenzero liked Warcraft very much, but he haven't practiced it for several years after being addicted to algorithms. Now, though he is playing with computer, he nearly losed and only his hero Pit Lord left. sevenzero is angry, he decided to cheat to turn defeat into victory. So he entered "whosyourdaddy", that let Pit Lord kill any hostile unit he damages immediately. As all Warcrafters know, Pit Lord masters a skill called Cleaving Attack and he can damage neighbour units of the unit he attacks. Pit Lord can choice a position to attack to avoid killing partial neighbour units sevenzero don't want to kill. Because sevenzero wants to win as soon as possible, he needs to know the minimum attack times to eliminate all the enemys.
 

 

Input
There are several cases. For each case, first line contains two integer N (2 ≤ N ≤ 55) and M (0 ≤ M ≤ N*N),and N is the number of hostile units. Hostile units are numbered from 1 to N. For the subsequent M lines, each line contains two integers A and B, that means A and B are neighbor. Each unit has no more than 4 neighbor units. The input is terminated by EOF.
 

 

Output
One line shows the minimum attack times for each case.
 

 

Sample Input
5 4
1 2
1 3
2 4
4 5
6 4
1 2
1 3
1 4
4 5
 

 

Sample Output
2
3
 

 

Author
sevenzero
 

 

Source
 

 

Recommend
zhouzeyong
 
 
 
 
 

这两天学习了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 }

 

posted @ 2013-04-17 15:58  Jack Ge  阅读(407)  评论(0编辑  收藏  举报