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

来源:互联网 发布:温州淘宝运营培训学校 编辑:程序博客网 时间:2024/04/30 02:06

题意:给你一个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;}


0 0
原创粉丝点击