HDU 3529 Bomberman - Just Search!(DLX可重复覆盖)

来源:互联网 发布:php set timezone 编辑:程序博客网 时间:2024/04/30 01:04

题意:

模仿炸弹人游戏,本题中炸弹的威力无限(无阻碍时威力为一整列一整行),给出至大15*15的地图,问最少同时放置几个炸弹,可以将墙一下炸完。

思路:

对每个墙编号,遍历图求出把炸弹放在每个点可以炸的墙,然后舞蹈链可重复匹配

代码:

#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const ll INF=0x3f3f3f3f3f3f3f3fll;const int maxn=230;int L[maxn*maxn],R[maxn*maxn],U[maxn*maxn],D[maxn*maxn];//节点的上下左右四个方向的链表int C[maxn*maxn],H[maxn],cnt[maxn],vis[maxn];//C列H行cnt列链表中元素个数int n,m,id,fans,u,v,q,p,s,a[20][20],cut;char mp[20][20];set< set<int> >poi;bool flag;void init(){    for(int i=0;i<=cut;i++){        cnt[i]=0;U[i]=D[i]=i;        L[i+1]=i;R[i]=i+1;    }    R[cut]=0;id=cut+1;    memset(H,-1,sizeof(H));}void Link(int r,int c){    cnt[c]++;C[id]=c;    U[id]=U[c];D[U[c]]=id;    D[id]=c;U[c]=id;    if(H[r]==-1) H[r]=L[id]=R[id]=id;    else{        L[id]=L[H[r]];R[L[H[r]]]=id;        R[id]=H[r];L[H[r]]=id;    }    id++;}void Remove(int Size){    for(int j=D[Size];j!=Size;j=D[j])        L[R[j]]=L[j],R[L[j]]=R[j];}void Resume(int Size){    for(int j=D[Size];j!=Size;j=D[j])        L[R[j]]=R[L[j]]=j;}int h(){    int sum=0;    memset(vis,0,sizeof(vis));    for(int i=R[0];i;i=R[i]){        if(vis[i]) continue;        sum++;        for(int j=D[i];j!=i;j=D[j]){            for(int k=R[j];k!=j;k=R[k])                vis[C[k]]=1;        }    }    return sum;}void Dance(int k){    int mm=maxn,pos;    if(k+h()>=fans) return;    if(!R[0]){        if(k<fans) fans=k;        return;    }    for(int i=R[0];i;i=R[i])        if(mm>cnt[i]) mm=cnt[i],pos=i;    for(int i=D[pos];i!=pos;i=D[i])    {        Remove(i);        for(int j=R[i];j!=i;j=R[j]) Remove(j);        Dance(k+1);        for(int j=R[i];j!=i;j=R[j]) Resume(j);        Resume(i);    }}void get(int x,int y){    set<int> al;    for(int i=x-1;i>0;i--){        if(a[i][y]==-1)            break;        else if(a[i][y]){            al.insert(a[i][y]);            break;        }    }    for(int i=x+1;i<n;i++){        if(a[i][y]==-1)            break;        else if(a[i][y]){            al.insert(a[i][y]);            break;        }    }    for(int i=y-1;i>0;i--){        if(a[x][i]==-1)            break;        else if(a[x][i]){            al.insert(a[x][i]);            break;        }    }    for(int i=y+1;i<m;i++){        if(a[x][i]==-1)            break;        else if(a[x][i]){            al.insert(a[x][i]);            break;        }    }    if(poi.find(al)==poi.end()){        s++;        poi.insert(al);        //cout<<s<<' '<<x<<' '<<y<<endl;        for(set <int>::iterator it=al.begin();it!=al.end();it++){            Link(s,*it);            //cout<<*it;        }        //cout<<endl;    }}int main(){    while(scanf("%d %d",&n,&m)!=-1){        getchar();        cut=0;        for(int i=0;i<n;i++)            gets(mp[i]);        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                if(mp[i][j]=='#')                    a[i][j]=++cut;                else if(mp[i][j]=='*')                    a[i][j]=-1;                else                    a[i][j]=0;            }            //getchar();        }        init();        s=0;        poi.clear();        for(int i=1;i<n;i++){            for(int j=1;j<m;j++){                if(a[i][j]==0)                get(i,j);            }        }        fans=cut;        Dance(0);        printf("%d\n",fans);    }    return 0;}

Bomberman has been a very popular game ever since it was released. As you can see above, the game is played in an N*M rectangular room. Bomberman can go around the room and place bombs. Bombs explode in 4 directions with radius r. To finish a stage, bomberman has to defeat all the foes with his bombs and find an exit behind one of the walls. 
Since time is limited, bomberman has to do this job quite efficiently. Now he has successfully defeated all the foes, and is searching for the exit. It's really troublesome to destroy the walls one by one, so he's asking for your help to calculate the minimal number of bombs he has to place in order to destroy all the walls, thus he can surely find the exit. 
Input
The input contains several cases. Each case begins with two integers: N and M(4 <= N, M <= 15). N lines follow, each contains M characters, describing the room. A '*' means a concrete wall which can never be destroyed, a '#' is an ordinary wall that can be destroyed by a single bomb, a '.' is an empty space where bombs can only be placed. There're at most 30 ordinary walls. The borders of the room is always surrounded by concrete walls, as you can see from the samples. You may assume that the explosion radius r is infinite, so that an explosion can reach as far as possible until it meets a wall and destroys it if it's an ordinary one. Proceed until the end of file.
Output
For each case, output the minimal number of bombs that should be placed to destroy all the ordinary walls. Note that two bombs can't be placed at the same position and all bombs explode simultaneously, which makes the result for the second sample to be 3 instead of 2. You may assume that there's always a solution.
Sample Input
9 11************#.#...#.#**.*.*.*.*.**.........**.*.*.*.*.**....#....**.*.*.*.*.**....#....************3 13**************..##...##..**************
Sample Output
33


0 0