icpc live archive6454(状压搜索)

https://icpcarchive.ecs.baylor.edu/external/64/6454.pdf

求最少的灯照亮所有.的区域,但不能照到#号区域,可以照到界限之外,每个.号上只能放一盏灯。灯照的区域为L形,灯在拐角处。大多数灯是这样没错,但有一盏灯比较特殊,可以是L的其他三种旋转体。

状态压缩搜索,状态为放置的灯的状态,(.)点最多只有15个,做好序号可以直接存进一个int型里。

代码(中间有一些比较繁琐):

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#include<cstring>
#include<algorithm>
#define LL long long
#define MOD 100000007
#define INF 0x3f3f3f3f
using namespace std;

const int maxn=202;
char g[maxn][maxn];
int opp[maxn][maxn];
bool done[100000];
int n,m,k,cnt,sx,sy,point;
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
int aimx[20],aimy[20];
struct node
{
    int w,key,stat,no;//w为走的步数,key为可以放灯的点状态,stat为灯照亮的区域(一定是15个点中的嘛),no为还有几个特殊灯没放。
    node(int ww=0,int k=0,int st=0,int n=0)
    {
        w=ww;key=k;stat=st;no=n;
    }
};
bool is_ill(int x,int y)
{
    return x<0||x>=n||y<0||y>=m;
}

int bfs()
{
    queue<node>q;
    memset(done,0,sizeof done);
    q.push(node(0,k,k,1));
    done[k]=1;
    while(!q.empty())
    {
        node e=q.front();q.pop();
        for(int i=0;i<cnt;i++)
        if(e.key&(1<<i))
        {
            if((is_ill(aimx[i]-1,aimy[i])||g[aimx[i]-1][aimy[i]]=='.')&&(is_ill(aimx[i],aimy[i]+1)||g[aimx[i]][aimy[i]+1]=='.'))//普通灯
            {
                int curstat=e.stat;
                if(!is_ill(aimx[i],aimy[i]))curstat&=~(1<<opp[aimx[i]][aimy[i]]);
                if(!is_ill(aimx[i]-1,aimy[i]))curstat&=~(1<<opp[aimx[i]-1][aimy[i]]);
                if(!is_ill(aimx[i],aimy[i]+1))curstat&=~(1<<opp[aimx[i]][aimy[i]+1]);
                if(curstat==0)return e.w+1;
                if(!done[e.key^(1<<i)])
                {
                    q.push(node(e.w+1,e.key^(1<<i),curstat,e.no));
                    done[e.key^(1<<i)]=1;
                }

            }
            if(!e.no)continue;//以下为三个特殊灯,再次做判断是否还有特殊灯未放
            if((is_ill(aimx[i]-1,aimy[i])||g[aimx[i]-1][aimy[i]]=='.')&&(is_ill(aimx[i],aimy[i]-1)||g[aimx[i]][aimy[i]-1]=='.'))
            {
                int curstat=e.stat;
                if(!is_ill(aimx[i],aimy[i]))curstat&=~(1<<opp[aimx[i]][aimy[i]]);
                if(!is_ill(aimx[i]-1,aimy[i]))curstat&=~(1<<opp[aimx[i]-1][aimy[i]]);
                if(!is_ill(aimx[i],aimy[i]-1))curstat&=~(1<<opp[aimx[i]][aimy[i]-1]);
                if(curstat==0)return e.w+1;
                if(!done[e.key^(1<<i)])
                {
                    q.push(node(e.w+1,e.key^(1<<i),curstat,0));
                    done[e.key^(1<<i)]=1;
                }

            }
            if((is_ill(aimx[i]+1,aimy[i])||g[aimx[i]+1][aimy[i]]=='.')&&(is_ill(aimx[i],aimy[i]+1)||g[aimx[i]][aimy[i]+1]=='.'))
            {
                int curstat=e.stat;
                if(!is_ill(aimx[i],aimy[i]))curstat&=~(1<<opp[aimx[i]][aimy[i]]);
                if(!is_ill(aimx[i]+1,aimy[i]))curstat&=~(1<<opp[aimx[i]+1][aimy[i]]);
                if(!is_ill(aimx[i],aimy[i]+1))curstat&=~(1<<opp[aimx[i]][aimy[i]+1]);
                if(curstat==0)return e.w+1;
                if(!done[e.key^(1<<i)])
                {
                    q.push(node(e.w+1,e.key^(1<<i),curstat,0));
                    done[e.key^(1<<i)]=1;
                }

            }
            if((is_ill(aimx[i]+1,aimy[i])||g[aimx[i]+1][aimy[i]]=='.')&&(is_ill(aimx[i],aimy[i]-1)||g[aimx[i]][aimy[i]-1]=='.'))
            {
                int curstat=e.stat;
                if(!is_ill(aimx[i],aimy[i]))curstat&=~(1<<opp[aimx[i]][aimy[i]]);
                if(!is_ill(aimx[i]+1,aimy[i]))curstat&=~(1<<opp[aimx[i]+1][aimy[i]]);
                if(!is_ill(aimx[i],aimy[i]-1))curstat&=~(1<<opp[aimx[i]][aimy[i]-1]);
                if(curstat==0)return e.w+1;
                if(!done[e.key^(1<<i)])
                {
                    q.push(node(e.w+1,e.key^(1<<i),curstat,0));
                    done[e.key^(1<<i)]=1;
                }
            }
        }
    }
    return -1;
}

int main()
{
    int a,b,kk;
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        for(int i=0;i<n;i++)
            scanf("%s",g[i]);
        memset(opp,-1,sizeof opp);
        cnt=0;k=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            if(g[i][j]=='.')aimx[cnt]=i,aimy[cnt]=j,opp[i][j]=cnt,k|=1<<(cnt++);

        if(!cnt)
        {
            printf("0\n");
            continue;
        }
        printf("%d\n",bfs());
    }
    return 0;
}

你可能感兴趣的:(icpc live archive6454(状压搜索))