HDU 3681 Prison Break (二分答案+状压DP+bfs预处理)

来源:互联网 发布:佳能e618清零软件 编辑:程序博客网 时间:2024/05/17 07:47

题意:

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


分析:

把F,G,Y三种类型的点找出来,进行讨论,首先bfs处理出来各个点之间的最短路。现在题目就变成了:求一幅图中满足走遍所有Y点的条件,机器人存储的电量最少。

由于点最多只有15个,状压dp来处理。二分机器人的储电量,每次用dp来做判定条件。


#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int n,m;char map[22][22];int dist[22][22],vis[22][22];int dx[] = {0,0,-1,1};int dy[] = {1,-1,0,0};int dp[22][1<<16];struct node {    int x,y,step;    char c;}q[1111],p[20];int head,tail,cnt,st,numY;int bfs(int x,int y,int xx,int yy) {    head = 0; tail = 0;    memset(vis,0,sizeof(vis));    q[head].x = x;    q[head].y = y;    q[head++].step = 0;    vis[x][y] = 1;    while(head != tail) {        node t = q[tail++];        node tt;        if(t.x == xx && t.y == yy) {            return t.step;        }        for(int i=0; i<4; i++) {            tt.x = t.x + dx[i];            tt.y = t.y + dy[i];            if(tt.x<0 || tt.x>=n || tt.y<0 || tt.y >=m || map[tt.x][tt.y] == 'D' || vis[tt.x][tt.y] ) continue;            tt.step = t.step + 1;            vis[tt.x][tt.y] = 1;            q[head++] = tt;        }    }    return -1;}void getdist() {    for(int i=0; i<cnt; i++) {        for(int j=i; j<cnt; j++) {            if(i == j) dist[i][j] = 0;            else {                dist[i][j] = bfs(p[i].x,p[i].y,p[j].x,p[j].y);                dist[j][i] = dist[i][j];            }        }    }}int getY(int x) {    int id = 0;    int num = 0;    while(x) {        if((x & 1) && p[id].c == 'Y') num ++;        x = x >> 1;        id ++;    }    return num;}int judge(int va) {    memset(dp,-1,sizeof(dp));    int total = 1 << cnt;    dp[st][1 << st] = va;    for(int j=0; j<total; j++) {        if((j & (1 << st)) == 0) continue;        for(int i=0; i<cnt; i++) {            if(i == st) continue;            for(int k=0; k<cnt; k++) {                if(dist[i][k] == -1) continue;                if(dist[i][k] <= dp[k][j ^ (1 << i)]) {                    if(p[i].c == 'G') dp[i][j] = va;                    else dp[i][j] = max(dp[i][j],dp[k][j ^ (1 << i)] - dist[i][k]);                }            }        }    }    for(int j=0; j<total; j++) {        if((j & (1 << st)) == 0) continue;        if(getY(j) == numY) {            for(int i=0; i<cnt; i++) {                if(p[i].c == 'Y' && dp[i][j] != -1) return 1;            }        }    }    return 0;}void solve() {    getdist();    int l = 1, r = 250, mid;    int minn = 251;    while(l <= r) {        mid = (l + r) >> 1;        if(judge(mid)) {            minn = min(minn,mid);            r = mid - 1;        } else l = mid + 1;    }    if(minn == 251) puts("-1");    else printf("%d\n",minn);}int main() {    while(scanf("%d%d",&n,&m)) {        if(n == 0 && m == 0) break;        cnt = 0; numY = 0;        for(int i=0; i<n; i++) scanf("%s",map[i]);        for(int i=0; i<n; i++) {            for(int j=0; j<m; j++) {                if(map[i][j] == 'F') {                    p[cnt].x = i; p[cnt].y = j;                    p[cnt].c = 'F';                    st = cnt;                    cnt ++;                }                if(map[i][j] == 'G') {                    p[cnt].x = i; p[cnt].y = j;                    p[cnt].c = 'G';                    cnt++;                }                if(map[i][j] == 'Y') {                    numY ++;                    p[cnt].x = i; p[cnt].y = j;                    p[cnt].c = 'Y';                    cnt++;                }            }        }        solve();    }    return 0;}