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(状压dp+二分)

题目链接 Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/...
  • fouzhe
  • fouzhe
  • 2016年10月15日 21:36
  • 133

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

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one d...
  • faithdongdong
  • faithdongdong
  • 2014年08月28日 10:55
  • 1109

HDU 3681 Prison Break floyd+状压+二分

题目链接:点击打开链接 题意: 给定n*m的矩阵: F:起点(有且仅有一个) D:坏点(不能走到这个点) G:能量池(走到这个点可以选择使用这个点的能量池,把电池充满,也可以暂时不用,只能使...
  • qq574857122
  • qq574857122
  • 2014年11月14日 17:48
  • 797

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意:给一张N * M的图,只能上下左右移动,每移动一格消耗一点能量,其中F是起点...
  • u013742332
  • u013742332
  • 2015年07月24日 20:52
  • 333

HDU 3681 Prison Break

/* 给一个n*m的图,F代表起点,G代表充电池,一个充电池只能用一次,但可以用多个充电池,只能把电池充到最大(原始的电量),可以走过不用,D不能走, 问的是把所有的Y走一遍的原始的电量是多少 ...
  • u013491149
  • u013491149
  • 2015年01月26日 14:51
  • 397

HDU 3681 - Prison Break

题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=3681   囧,BFS+二分+DFS。   一开始懒,想直接BFS过这题,结果TLE还想着用剪...
  • diannaok
  • diannaok
  • 2012年09月19日 13:59
  • 589

hdu 3681 Prison Break

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one d...
  • magicnumber
  • magicnumber
  • 2011年08月01日 00:22
  • 1573

HDU 3681 Prison Break

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T...
  • overload1997
  • overload1997
  • 2016年10月20日 23:59
  • 109

HDU 3681 Prison Break

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one...
  • jtjy568805874
  • jtjy568805874
  • 2015年07月18日 23:13
  • 208

hdu 3681 Prison Break (BFS+状压)

2010杭州赛区的题目 题意: 机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,且电量最少,并求出该最小电量。 题解: 像这种题目暂时找不到很好的解决方法,...
  • My_ACM_Dream
  • My_ACM_Dream
  • 2015年02月08日 20:01
  • 372
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:HDU 3681 Prison Break (状压DP+二分)
举报原因:
原因补充:

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