hdu 3681 Prison Break (BFS+状压)

2010杭州赛区的题目

题意:

机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,且电量最少,并求出该最小电量。

题解:

像这种题目暂时找不到很好的解决方法,可以试着想想暴力的方法,就是枚举每个电量是否满足,一般这样的枚举都是用二分,对于判断是否满足条件可以用状压dp来解决。我们首先要预处理出充电地点和发电站两两之间的最短路径可以用bfs解决,然后将这些点压缩TSP问题。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long lld;
const int oo=0x3f3f3f3f;
const lld OO=1LL<<61;
const int Mod=1000000007;
int dis[20][20][20][20];
int n,m,full,cnt;
int tagS;//目标状态 关掉所有发电机的状态
int dp[(1<<16)+5][20];
char maze[20][20];
int start;
struct POINT
{
    int x,y;
}po[20];
int d[4][2]={
    {1,0},{-1,0},{0,1},{0,-1}
};

void intput()
{
    tagS=cnt=0;
    for(int i=1;i<=n;i++)
    {
        getchar();
        for(int j=1;j<=m;j++)
        {
            maze[i][j]=getchar();
            if(maze[i][j]=='Y'||maze[i][j]=='F')
            {
                if(maze[i][j]=='F')
                    start=cnt;
                tagS|=(1<<cnt);
                po[cnt].x=i;
                po[cnt].y=j;
                cnt++;
            }
            else if(maze[i][j]=='G')
            {
                po[cnt].x=i;
                po[cnt].y=j;
                cnt++;
            }
        }
    }
}

void bfs(int sx,int sy)
{
    POINT q[300],next,now;
    int front,rear;
    front=rear=0;
    now.x=sx;
    now.y=sy;
    q[rear++]=now;
    dis[sx][sy][sx][sy]=0;
    while(front<rear)
    {
        now=q[front++];
        for(int k=0;k<4;k++)
        {
            next.x=now.x+d[k][0];
            next.y=now.y+d[k][1];
            if(next.x>=1&&next.x<=n&&next.y>=1&&next.y<=m)
            {
                if(maze[next.x][next.y]!='D')
                {
                    if(dis[sx][sy][next.x][next.y]==-1)
                    {
                        dis[sx][sy][next.x][next.y]=dis[sx][sy][now.x][now.y]+1;
                        q[rear++]=next;
                    }
                }
            }
        }
    }
}

bool judge(int V)
{
    full=(1<<cnt)-1;
    int res=-1;
    memset(dp,-1,sizeof dp);
    dp[1<<start][start]=V;
    for(int s=0;s<=full;s++)
    {
        for(int i=0;i<cnt;i++)
        {
            if(dp[s][i]==-1)continue;
            if(!(s&(1<<i)))continue;
            if(((s&tagS)&tagS)==tagS)//如果发电站都关闭了
                res=max(res,dp[s][i]);
            for(int j=0;j<cnt;j++)
            {
                if(s&(1<<j))continue;
                if(i==j)continue;
                int temp=dis[po[i].x][po[i].y][po[j].x][po[j].y];
                if(temp==-1)continue;
                temp=dp[s][i]-temp;
                if(temp<0)continue;
                int st=s|(1<<j);
                dp[st][j]=max(dp[st][j],temp);
                if(maze[po[j].x][po[j].y]=='G')dp[st][j]=V;
            }
        }
    }
    return res>=0;
}

void solve()
{
    memset(dis,-1,sizeof dis);
    for(int i=0;i<cnt;i++)
        bfs(po[i].x,po[i].y);
    int l=0,r=300,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(judge(mid))
            r=mid-1;
        else
            l=mid+1;
    }
    if(l==301)l=-1;
    printf("%d\n",l);
}

int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        intput();
        solve();
    }
    return 0;
}
/**
5 5
GDDSS
SSSFS
SYGYS
SGSYS
SSYSS
0 0

*/


你可能感兴趣的:(hdu 3681 Prison Break (BFS+状压))