HDU 3681 Prison Break BFS+状态压缩DP

思路:先BFS出关键点(起点,电池,开关)之间的最短路

然后状态压缩DP dp[当前位置][状态]=电池电量

二分答案即可

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
using namespace std;
const int N=16;
#define for if(0); else for
struct Point{
    int x,y;
    Point(){x=y=0;}
    Point(int xx,int yy){x=xx;y=yy;}
};

const int inf=0x0f0f0f0f;
int n,m;
Point que[N*N+100];
int vis[N][N];
int d[N][N];
int td[N][N];
char g[N][N];
int no[N][N];
Point P[N];
int nG,nY,num;

void bfs(int s,int d[],int td[][N]){
    for(int i=0;i<N;i++) d[i]=inf;
    d[s]=0;
    memset(vis,0,sizeof(vis));
    memset(td,0x0f,N*N*sizeof(int));
    int st=0,ed=0;
    int dx[4]={0,0,1,-1};
    int dy[4]={1,-1,0,0};
    que[ed++]=P[s];
    td[P[s].x][P[s].y]=0;
    vis[P[s].x][P[s].y]=1;
    while(st!=ed){
        Point cur=que[st++];
        int curdis=td[cur.x][cur.y];
        if(no[cur.x][cur.y]!=-1){
            d[no[cur.x][cur.y]]=curdis;
        }
        for(int i=0;i<4;i++){
            Point np=Point(cur.x+dx[i],cur.y+dy[i]);
            if(!vis[np.x][np.y] && g[np.x][np.y]!='D' && g[np.x][np.y]!=0){
                vis[np.x][np.y]=1;
                td[np.x][np.y]=curdis+1;
                que[ed++]=np;
            }
        }
    }
}
int dp[15][1<<15];
bool can(int maxbatt){
    int maxmask=1<<(num-1);
    int sta=maxmask-1;
    for(int i=0;i<num;i++) memset(dp[i],-1,maxmask*sizeof(int));
    dp[0][sta]=maxbatt;
    for(int stat=sta;stat>=0;stat--){
        for(int i=1;i<num;i++){
            int mm=1<<(i-1);
            for(int j=0;j<num;j++) if(j!=i) {
                int cost=d[i][j];
                if(dp[j][stat]-cost>=0) dp[i][stat]=max(dp[i][stat],dp[j][stat]-cost);
                if(~stat&mm){
                    int prev=stat^mm;
                    if(i<=nG) {
                        if(dp[j][prev]-cost>=0) {
                            dp[i][stat]=maxbatt;
                        }
                    }else{
                        if(dp[j][prev]-cost>=0) dp[i][stat]=max(dp[i][stat],dp[j][prev]-cost);
                    }
                }
            }
            if(stat<(1<<nG) && dp[i][stat]>=0) return true;
        }
    }
    return false;
}

int main() {
    while(scanf("%d%d",&n,&m)&&(n||m)){
        memset(g,0,sizeof(g));
        for(int i=1;i<=n;i++) scanf("%s",g[i]+1);
        nG=nY=num=0;
        memset(no,-1,sizeof(no));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) if(g[i][j]=='F') P[num]=Point(i,j),no[i][j]=num++;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) if(g[i][j]=='G') P[num]=Point(i,j),nG++,no[i][j]=num++;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++) if(g[i][j]=='Y') P[num]=Point(i,j),nY++,no[i][j]=num++;
        for(int i=0;i<num;i++){
            bfs(i,d[i],td);
        }
        bool haveans=true;
        for(int i=nG+1;i<num;i++) if(d[0][i]==inf) haveans=false;
        int left=0,right=n*m;
        int mid,ans=-1;
        if(haveans){
                while(left<=right){
                mid=(left+right)>>1;
                if(can(mid)){
                    ans=mid;
                    right=mid-1;
                }else left=mid+1;
            }
        }
        if(nY==0) ans=0;
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2012-08-05 17:15  编程菜菜  阅读(667)  评论(0编辑  收藏  举报