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

原创 2015年07月08日 08:45:45

题意:给你一个n*m的图,机器人只能上下左右移动,移动一格消耗一点能量,F是起点,D是不可经过的点,S是空地,G是充能的站点,Y是必须经过的点,整个过程机器人必须让自己的能量尽可能的少,并且经过所有的Y,问机器人的最小能量容量是多少。

思路:因为‘G’和‘Y’的数量和T小于等于15,所以用这个来表示状态。

设'Y'的点数为Y。那么F标号为0,'Y'的点依次标号为1,2,....Y 。‘G’标号为Y+1,Y+2,....T。

状态S:第i位为1表示经过了第i-1个点。以此来二分答案。

设能量容量为k,dp[S][v]为经过状态S中的所有点,最后到达v的最大剩余能量。

状态转移方程:dp[S][v] = max(dp[S][v],dp[S-{v}][u] - G[u][v]) 如果dp[S][v] >= 0 且v > Y 的话,dp[S][v] = k。


我的代码:

#include<cstdio>
#include<iostream>
#include<map>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;
typedef pair<int,int> P;
const int maxn = 15;
const int inf = 0x3f3f3f3f;
const int dx[4] = {1,-1,0,0};
const int dy[4] = {0,0,1,-1};

char maps[maxn][maxn];
int n,m,T,G[maxn][maxn];
int dp[1<<maxn][maxn];
map<P,int> M;
int Y;

struct Nod{
    int x,y,step;
};
bool vis[maxn][maxn];
queue<Nod> que;

void init(){
    M.clear();
    int tmp = 1 << maxn;
    //memset(G,-1,sizeof(G));
    for(int i=0;i<maxn;i++) fill(G[i],G[i]+maxn,inf);
    //for(int i=0;i<tmp;i++) fill(dp[i],dp[i]+maxn,inf);
}

void bfs(int x,int y,int s){
    //cout<<x<<" "<<y<<" "<<s<<endl;
    Nod cur,next;
    memset(vis,0,sizeof(vis));
    cur.x = x;cur.y = y;cur.step = 0;
    que.push(cur);
    vis[x][y] = true;

    while(!que.empty()){
        cur = que.front();que.pop();
        //cout<<cur.x<<" "<<cur.y<<" "<<cur.step<<endl;
        if(cur.step > 0 && (maps[cur.x][cur.y] == 'G' || maps[cur.x][cur.y] == 'Y')){
            int pos = M[P(cur.x,cur.y)];
            G[s][pos] = cur.step;
        }
        for(int i=0;i<4;i++){
            next.x = cur.x + dx[i];
            next.y = cur.y + dy[i];
            next.step = cur.step + 1;
            if(next.x < 0 || next.x >= n || next.y < 0 || next.y >= m || vis[next.x][next.y] || maps[next.x][next.y] == 'D') continue;
            vis[next.x][next.y] = true;
            que.push(next);
        }
    }
}

void build_graph(){
    T = 1;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maps[i][j] == 'Y') M.insert(make_pair(P(i,j),T++));
            if(maps[i][j] == 'F') M.insert(make_pair(P(i,j),0));
        }
    }
    Y = T - 1;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maps[i][j] == 'G') M.insert(make_pair(P(i,j),T++));
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(maps[i][j] == 'F' || maps[i][j] == 'Y' || maps[i][j] == 'G'){
                bfs(i,j,M[P(i,j)]);
            }
        }
    }
}

bool check(int S){
    for(int i=0;i<Y;i++){
        if(!(S >> i & 1)) return false;
    }
    return true;
}

bool binSearch(int k){
    int Ed = 1 << T;
    bool flag;
    memset(dp,-1,sizeof(dp));
    dp[0][0] = k;
    for(int S = 1; S < Ed ; S++){
        flag = false;
        for(int v = 1; v <= T ; v++){
            if(!(S >> (v - 1) & 1)) continue;
            int S0 = S - (1 << (v - 1));
            if(S0 == 0){
                dp[S][v] = max(dp[S][v],dp[0][0] - G[0][v]);
            }
            else{
                for(int u = 1;u <= T;u++){
                if(!(S0 >> (u - 1) & 1) || dp[S0][u] == -1) continue;
                dp[S][v] = max(dp[S][v],dp[S0][u] - G[u][v]);
                }
            }
            if(dp[S][v] >= 0){
                flag = true;
                if(v > Y) dp[S][v] = k;
            }
        }
        if(check(S) && flag){
            return true;
        }
    }
    return false;
}

void solve(){
    T -= 1;
    int lb = 0,rb = 1000;
    while(rb - lb > 1){
        int mid = (lb + rb) >> 1;
        if(binSearch(mid)) rb = mid;
        else lb = mid;
    }
    if(rb == 1000) printf("-1\n");
    else printf("%d\n",rb);
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        if(n + m == 0) break;
        init();
        for(int i=0;i<n;i++) scanf("%s",maps[i]);
        build_graph();
        solve();
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 3681 Prison Break(bfs+二分+状压DP)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T...

HDU3681 Prison Break(壮压dp+二分+bfs)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意:一个机器人想越狱,他只能带一定电量的电池,'S'表示道路可行,'G'表示充电器(充满),只...

HDU 3681 Prison Break (搜索+状压dp)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意: 一个机器人想越狱,他只能带一定电量的电池,'S'表示道路可行,'G'表示充电器...

HDU3681 Prison Break(状压dp)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one d...

HDU 3681 Prison Break - 状压dp【TSP】

题目描述题目大意:一个机器人想越狱,监狱是一个N*M的网格。每走一格,耗费1个单位的电量。他只能带一定电量的电池, ‘F’表示起点, ‘S’表示道路可行, ‘D’表示不能经过的地点。 ‘G’表示充电器...

HDU3681 Prison Break【状压】

题意:给一张图,机器人从F出发,关闭所有Y,问它的最小电池储量,图中G可以把电池充满 思路:把图中的F和G、Y拿出来用作状压DP的点,点之间最短距离跑下bfs。二分答案,用状压DP判断下这个...
  • wjw1340
  • wjw1340
  • 2017年08月09日 16:39
  • 53

hdu3681 Prison Break (dfs+二分+状态压缩)

题意:一个机器人一开始在F,D表示障碍,Y表示开关,G表示充电器。 机器人每走一步消耗一点能量,走到充电器可以瞬间充满电(每个充电器只能充一次),现在要打开所有的开关(每个开关也只用打开一次),问最...

HDU-3681 Prison Break (bfs + 二分枚举)

题目大意:要求主角打开所有开关从而能打开监狱从而逃走。 要求:主角梅走一步都会消耗一单位的能量,不能通过'D',‘G’是补充能量的地方(意味着在此处主角可将能量补到电池容量大小),可以补满能量,...

hdu 3681 Prison Break

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one d...

HDU3681Prison Break(状态压缩+BFS)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 3681 Prison Break (状压DP+二分)
举报原因:
原因补充:

(最多只允许输入30个字)