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
", g.ansd);
147     }
148     return 0;
149 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538573.html