可以重复的点覆盖, 写法和一般的DLX 很相似,但是在找到选择一行的时候,只删去这一行上所有点的列。 还要注意的是启发函数起了很大的剪枝作用。
Problem 1686 神龙的难题
Accept: 331 Submit: 1111 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 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1 2 2 4 4 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0 2 2
Sample Output
4 1
Source
FOJ月赛-2009年2月- TimeLoop#include <stdio.h> #include <string.h> #include <iostream> using namespace std; #define N 1000000 #define INF 0x3ffffff int U[N],D[N],R[N],L[N],num[N],col[N],line[N],H[N]; int g[20][20],tg[250][250];; int n,m; int tn,tm; int nn,mm; int head; int id; int mi; void prepare() { for(int i=0;i<=mm;i++) { num[i]=0; U[i]=i; D[i]=i; R[i]=i+1; L[i+1]=i; } R[mm]=0; L[0]=mm; memset(H,-1,sizeof(H)); // 列的头指针 } void link(int n1,int m1) { id++; ++num[ line[id]=m1 ]; col[id]=n1; D[id]=D[m1]; U[ D[m1]]=id; U[id]=m1; D[m1]=id; if(H[n1]<0) H[n1]=L[id]=R[id]=id; else { L[ R[ H[n1] ] ]=id; R[id]=R[H[n1]]; L[id]=H[n1]; R[ H[n1] ]=id; } } void build() { id=mm; prepare(); for(int i=0;i<=n-tn;i++) { for(int j=0;j<=m-tm;j++) { int flag=0; for(int i1=1;i1<=tn;i1++) for(int j1=1;j1<=tm;j1++) { if(g[i+i1][j+j1]!=0) { flag=1; link(nn,g[i+i1][j+j1]); } } nn++; } } } void remove(int s) { for(int i=D[s];i!=s;i=D[i]) { L[R[i]]=L[i]; R[L[i]]=R[i]; } } void resume(int s) { for(int i=D[s];i!=s;i=D[i]) { L[ R[i] ]=i; R[ L[i] ]=i; } } /*int h() // 求出填满所有列所需的最小行 { int mark[N]; memset(mark,0,sizeof(mark)); }*/ void print() { memset(tg,0,sizeof(tg)); for(int i=R[head];i!=head;i=R[i]) { for(int j=D[i];j!=i;j=D[j]) tg[col[j]][line[j]]=1; } for(int i=1;i<nn;i++) { for(int j=1;j<=mm;j++) printf("%d ",tg[i][j]); printf("\n"); } } int h() { int mark[250]; memset(mark,0,sizeof(mark)); int sum=0; for(int i=R[head];i!=head;i=R[i]) { if(mark[i]==0) { sum++; mark[i]=1; for(int j=D[i];j!=i;j=D[j]) for(int k=R[j];k!=j;k=R[k]) mark[line[k]]=1; } } return sum; } void dfs(int s) { if(s+h()>=mi) return ; if(R[head]==head) { mi=s; return ; } int tmi=INF,tu; for(int i=R[head];i!=head;i=R[i]) { if(num[i]<tmi) { tmi=num[i]; tu=i; } } for(int i=D[tu];i!=tu;i=D[i]) { remove(i); for(int j=R[i];j!=i;j=R[j]) remove(j); dfs(s+1); for(int j=L[i];j!=i;j=L[j]) resume(j); resume(i); } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { head=0; nn=1; mm=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&g[i][j]); if(g[i][j]==1) { mm++; g[i][j]=mm; } } scanf("%d%d",&tn,&tm); build(); mi=INF; //print(); dfs(0); printf("%d\n",mi); } return 0; }