题目链接:https://vjudge.net/problem/FZU-1686
Problem 1686 神龙的难题
Accept: 812 Submit: 2394
Time Limit: 1000 mSec Memory Limit : 32768 KB
Problem Description
Input
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的地方。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <set>
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int MAXN = 15*15+10;
const int MAXM = 15*15+10;
const int maxnode = MAXN*MAXM;
struct DLX
{
int n, m, size;
int U[maxnode], D[maxnode], L[maxnode], R[maxnode], Row[maxnode], Col[maxnode];
int H[MAXN], S[MAXM];
int ansd;
void init(int _n, int _m)
{
n = _n;
m = _m;
for(int i = 0; i<=m; i++)
{
S[i] = 0;
U[i] = D[i] = i;
L[i] = i-1;
R[i] = i+1;
}
R[m] = 0; L[0] = m;
size = m; //size是结点个数, 同时也是结点的编号
for(int i = 1; i<=n; i++) H[i] = -1;
}
void Link(int r, int c) //头插法
{
size++;
Row[size] = r;
Col[size] = c;
S[Col[size]]++;
D[size] = D[c];
U[D[c]] = size;
U[size] = c;
D[c] = size;
if(H[r]==-1) H[r] = L[size] = R[size] = size;
else
{
R[size] = R[H[r]];
L[R[H[r]]] = size;
L[size] = H[r];
R[H[r]] = size;
}
}
void remove(int c)
{
for(int i = D[c]; i!=c; i = D[i])
L[R[i]] = L[i], R[L[i]] = R[i];
}
void resume(int c)
{
for(int i = U[c]; i!=c; i = U[i])
L[R[i]] = R[L[i]] = i;
}
bool v[MAXM];
int f() //估计值,至少还需要多少次攻击
{
int ret = 0;
for(int c = R[0]; c!=0; c = R[c])
v[c] = true;
for(int c = R[0]; c!=0; c = R[c])
if(v[c])
{
ret++;
v[c] = false;
for(int i = D[c]; i!=c; i = D[i])
for(int j = R[i]; j!=i; j = R[j])
v[Col[j]] = false;
}
return ret;
}
void Dance(int d)
{
if(d+f()>=ansd) return; //剪枝
if(R[0]==0)
{
ansd = min(ansd, d);
return;
}
int c = R[0];
for(int i = R[0]; i!=0; i = R[i])
if(S[i]<S[c])
c = i;
for(int i = D[c]; i!=c; i = D[i])
{
remove(i);
for(int j = R[i]; j!=i; j = R[j]) remove(j);
Dance(d+1);
for(int j = L[i]; j!=i; j = L[j]) resume(j);
resume(i);
}
}
};
DLX g;
int a[20][20], id[20][20];
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)!=EOF)
{
int sz = 0;
for(int i = 0; i<n; i++)
for(int j = 0; j<m; j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]) id[i][j] = ++sz; //id为第几列
}
g.init(n*m, sz);
sz = 0;
int n1, m1;
scanf("%d%d",&n1, &m1);
for(int i = 0; i<n; i++) //枚举攻击的左上角
for(int j = 0; j<m; j++)
{
++sz; //sz为第几个攻击, 即第几行
for(int x = 0; x<n1 && x+i<n; x++) //枚举攻击范围
for(int y = 0; y<m1 && y+j<m; y++)
if(id[i+x][j+y])
g.Link(sz, id[i+x][j+y]); //sz为行,id为列
}
g.ansd = INF;
g.Dance(0);
printf("%d\n", g.ansd);
}
return 0;
}