FZU1686 神龙的难题 —— Dancing Links 可重复覆盖
题目链接:https://vjudge.net/problem/FZU-1686
Problem 1686 神龙的难题
Accept: 812 Submit: 2394
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间停止魔法停住时间,然后米格拉他就可以发出火球烧死敌人.米格拉想知道,他如何以最快的速度消灭敌人,减轻艾米莉的负担.
Input
数据有多组,你要处理到EOF为止.每组数据第一行有两个数,n,m,(1<=n,m<=15)表示这次任务的地区范围. 然后接下来有n行,每行m个整数,如为1表示该点有怪物,为0表示该点无怪物.然后接下一行有两个整数,n1,m1 (n1<=n,m1<=m)分别表示米格拉一次能攻击的行,列数(行列不能互换),假设米格拉一单位时间能发出一个火球,所有怪物都可一击必杀.
Output
输出一行,一个整数,表示米格拉消灭所有魔物的最短时间.
Sample Input
4 41 0 0 10 1 1 00 1 1 01 0 0 12 24 4 0 0 0 00 1 1 00 1 1 00 0 0 02 2
Sample Output
41
Source
FOJ月赛-2009年2月- TimeLoop
题解:
Dancing Links 矩阵:
1.行代表每一种攻击。
2.列代表每一个需要攻击的地方,即输入为1的地方。
代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <vector> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 #define ms(a,b) memset((a),(b),sizeof((a))) 13 using namespace std; 14 typedef long long LL; 15 const int INF = 0x3f3f3f3f; 16 const int MAXN = 15*15+10; 17 const int MAXM = 15*15+10; 18 const int maxnode = MAXN*MAXM; 19 20 struct DLX 21 { 22 int n, m, size; 23 int U[maxnode], D[maxnode], L[maxnode], R[maxnode], Row[maxnode], Col[maxnode]; 24 int H[MAXN], S[MAXM]; 25 int ansd; 26 void init(int _n, int _m) 27 { 28 n = _n; 29 m = _m; 30 for(int i = 0; i<=m; i++) 31 { 32 S[i] = 0; 33 U[i] = D[i] = i; 34 L[i] = i-1; 35 R[i] = i+1; 36 } 37 R[m] = 0; L[0] = m; 38 size = m; //size是结点个数, 同时也是结点的编号 39 for(int i = 1; i<=n; i++) H[i] = -1; 40 } 41 42 void Link(int r, int c) //头插法 43 { 44 size++; 45 Row[size] = r; 46 Col[size] = c; 47 S[Col[size]]++; 48 D[size] = D[c]; 49 U[D[c]] = size; 50 U[size] = c; 51 D[c] = size; 52 if(H[r]==-1) H[r] = L[size] = R[size] = size; 53 else 54 { 55 R[size] = R[H[r]]; 56 L[R[H[r]]] = size; 57 L[size] = H[r]; 58 R[H[r]] = size; 59 } 60 } 61 62 void remove(int c) 63 { 64 for(int i = D[c]; i!=c; i = D[i]) 65 L[R[i]] = L[i], R[L[i]] = R[i]; 66 } 67 68 void resume(int c) 69 { 70 for(int i = U[c]; i!=c; i = U[i]) 71 L[R[i]] = R[L[i]] = i; 72 } 73 74 bool v[MAXM]; 75 int f() //估计值,至少还需要多少次攻击 76 { 77 int ret = 0; 78 for(int c = R[0]; c!=0; c = R[c]) 79 v[c] = true; 80 for(int c = R[0]; c!=0; c = R[c]) 81 if(v[c]) 82 { 83 ret++; 84 v[c] = false; 85 for(int i = D[c]; i!=c; i = D[i]) 86 for(int j = R[i]; j!=i; j = R[j]) 87 v[Col[j]] = false; 88 } 89 return ret; 90 } 91 92 void Dance(int d) 93 { 94 if(d+f()>=ansd) return; //剪枝 95 if(R[0]==0) 96 { 97 ansd = min(ansd, d); 98 return; 99 } 100 101 int c = R[0]; 102 for(int i = R[0]; i!=0; i = R[i]) 103 if(S[i]<S[c]) 104 c = i; 105 for(int i = D[c]; i!=c; i = D[i]) 106 { 107 remove(i); 108 for(int j = R[i]; j!=i; j = R[j]) remove(j); 109 Dance(d+1); 110 for(int j = L[i]; j!=i; j = L[j]) resume(j); 111 resume(i); 112 } 113 } 114 }; 115 116 DLX g; 117 int a[20][20], id[20][20]; 118 int main() 119 { 120 int n, m; 121 while(scanf("%d%d",&n,&m)!=EOF) 122 { 123 int sz = 0; 124 for(int i = 0; i<n; i++) 125 for(int j = 0; j<m; j++) 126 { 127 scanf("%d",&a[i][j]); 128 if(a[i][j]) id[i][j] = ++sz; //id为第几列 129 } 130 131 g.init(n*m, sz); 132 sz = 0; 133 int n1, m1; 134 scanf("%d%d",&n1, &m1); 135 for(int i = 0; i<n; i++) //枚举攻击的左上角 136 for(int j = 0; j<m; j++) 137 { 138 ++sz; //sz为第几个攻击, 即第几行 139 for(int x = 0; x<n1 && x+i<n; x++) //枚举攻击范围 140 for(int y = 0; y<m1 && y+j<m; y++) 141 if(id[i+x][j+y]) 142 g.Link(sz, id[i+x][j+y]); //sz为行,id为列 143 } 144 g.ansd = INF; 145 g.Dance(0); 146 printf("%d\n", g.ansd); 147 } 148 return 0; 149 }