HDU 3681 Prison Break(BFS+二分+状态压缩DP)

用BFS处理每个点之间的距离,二分答案,用状态DP判断是否能够可以。

dp[i][j]表示当前位于i点已经遍历集合j时的最大能量值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=16;
const int inf=0x7f7f7f7f;
char grid[maxn][maxn];
int f[maxn][(1<<maxn)+10];
bool pool[maxn];
int num[maxn][maxn];
int g[maxn][maxn];
bool bvis[maxn][maxn];
int n,m;
int N,state;
const int mv[4][2]= {0,1,0,-1,1,0,-1,0};
struct Point
{
    int x,y,s;
    Point(int xx,int yy,int ss):x(xx),y(yy),s(ss) {}
};
void bfs(int x,int y)
{
    memset(bvis,0,sizeof(bvis));
    queue<Point> que;
    que.push(Point(x,y,0));
    bvis[x][y]=true;
    int now=num[x][y];
    g[now][now]=0;
    while(!que.empty())
    {
        Point p=que.front();
        que.pop();
        for(int i=0; i<4; ++i)
        {
            int nx=p.x+mv[i][0],ny=p.y+mv[i][1],ns=p.s+1;
            if(0<=nx&&nx<n&&0<=ny&&ny<m)
            {
                if(grid[nx][ny]=='D'||bvis[nx][ny])
                    continue;
                bvis[nx][ny]=true;
                if(grid[nx][ny]=='F'||grid[nx][ny]=='G'||grid[nx][ny]=='Y')
                {
                    g[now][num[nx][ny]]=ns;
                }
                que.push(Point(nx,ny,ns));
            }
        }
    }
}
bool prepare()
{
    memset(g,0x7f,sizeof(g));
    for(int i=0; i<n; ++i)
    {
        for(int j=0; j<m; ++j)
        {
            if(grid[i][j]=='F'||grid[i][j]=='G'||grid[i][j]=='Y')
                bfs(i,j);
        }
    }
    for(int i=0; i<N; ++i)
        for(int j=i+1; j<N; ++j)
        {
            if((state&(1<<i))&&(state&(1<<j)))
            {
                if(g[i][j]==inf)
                    return false;
            }
        }
    return true;
}
int getUpper(int sx,int sy)
{
    int res=0;
    int last=0;
    for(int i=1; i<N; ++i)
    {
        if(state&(1<<i))
        {
            res+=g[last][i];
            last=i;
        }
    }
    return res;
}
bool dp(const int full)
{
    memset(f,-1,sizeof(f));
    f[0][1]=full;
    for(int i=1; i<(1<<N); ++i)
    {
        for(int j=0; j<N; ++j)
        {
            if(!(i&(1<<j)))
            {
                for(int k=0; k<N; ++k)
                {
                    if(i&(1<<k))
                    {
                        int s=i|(1<<j);
                        if(f[k][i]>=g[j][k])
                        {
                            if(pool[j])
                                f[j][s]=full;
                            else
                                f[j][s]=max(f[j][s],f[k][i]-g[j][k]);
                        }
                    }
                }
            }
        }
    }
    for(int i=1; i<(1<<N); ++i)
    {
        for(int j=0; j<N; ++j)
        {
            if(f[j][i]>=0&&(i&state)==state)
            {
                return true;
            }
        }
    }
    return false;
}
int binSearch(int low,int high)
{
    int mid=low+(high-low)/2;
    while(low<high)
    {
        if(dp(mid))
            high=mid;
        else
            low=mid+1;
        mid=low+(high-low)/2;
    }
    return high;
}
int main()
{
    while(scanf("%d%d",&n,&m))
    {
        if(!n&&!m)
            break;
        memset(num,0,sizeof(num));
        memset(pool,0,sizeof(pool));

        state=0;
        N=0;
        int sx,sy;
        for(int i=0; i<n; ++i)
        {
            scanf("%s",grid[i]);
            for(int j=0; grid[i][j]; ++j)
            {
                if(grid[i][j]=='G'||grid[i][j]=='Y')
                {
                    N++;
                    if(grid[i][j]=='Y')
                        state|=(1<<N);
                    else
                        pool[N]=true;
                    num[i][j]=N;
                }
                else if(grid[i][j]=='F')
                {
                    num[i][j]=0;
                    state+=1;
                    sx=i;
                    sy=j;
                }
            }
        }
        ++N;
        if(!prepare())
            puts("-1");
        else
        {
            int up=getUpper(sx,sy);
            int ans=binSearch(0,up);
            printf("%d\n",ans);
        }

    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值