HDU3681(Prison Break)

题目链接:传送门

题目大意:给你一副n*m大小的图,‘D‘表示墙,‘F‘表示起点,‘S‘表示空地,‘G‘表示能源站,‘Y‘表示开关,一开始机器人处在‘F‘并有一个初始能量,每走一步会消耗一格能量

机器人需要在能量耗尽前经过所有‘Y‘至少一次,其中经过‘G‘可补满能量回初始值但每个‘G‘只能补一次,问至少需要几个能量才能达到要求。

题目思路:这个题感觉真的是很考验功底,集bfs,状态压缩DP,二分于一身,且实现细节不能马虎,实在是一道好题。

为什么说是状态压缩DP,You can assume that 1<=n,m<=15, and the sum of energy pools and power switches is less than 15.

从题意(每个点可以走多次)以及这句话可以看出这道题是用状态压缩DP,而解题关键是重新构造一副抽象图,把有效点抽离出来,而抽离点需要它们之间

的距离关系,这就需要bfs,最后就是二分枚举答案,取出最小值就是答案。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <algorithm>
  6 #include <cstring>
  7 #include <stack>
  8 #include <cctype>
  9 #include <queue>
 10 #include <string>
 11 #include <vector>
 12 #include <set>
 13 #include <map>
 14 #include <climits>
 15 #define lson root<<1,l,mid
 16 #define rson root<<1|1,mid+1,r
 17 #define fi first
 18 #define se second
 19 #define seg int root,int l,int r
 20 #define ping(x,y) ((x-y)*(x-y))
 21 #define mst(x,y) memset(x,y,sizeof(x))
 22 #define mcp(x,y) memcpy(x,y,sizeof(y))
 23 #define Min(x,y) (x<y?x:y)
 24 #define Max(x,y) (x>y?x:y)
 25 using namespace std;
 26 #define gamma 0.5772156649015328606065120
 27 #define MOD 1000000007
 28 #define inf 0x3f3f3f3f
 29 #define N 1000
 30 #define maxn 1000050
 31 typedef long long LL;
 32 typedef pair<int,int> PII;
 33
 34 char pic[20][20];
 35 int dis[20][20];      ///bfs中所用数组,记录的是搜索的点到其它有效点之间的距离
 36 int dp[1<<17][20];    ///状态压缩DP转移数组,二维表示最后到达的是第几个点
 37 int xx[20],yy[20];    ///抽离有效点,把横纵坐标保存下来
 38 int d[20][20];        ///有效点对之间的距离
 39 int state,cnt,ss,n,m; ///cnt表示有效点个数,state表示符合题意条件的值(用于匹配答案)
 40 int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
 41
 42 void bfs(int s){
 43     queue<int>q;
 44     q.push(xx[s]);q.push(yy[s]);
 45     dis[xx[s]][yy[s]]=0;
 46     while(!q.empty()){
 47         int x=q.front();q.pop();
 48         int y=q.front();q.pop();
 49         for(int i=0;i<4;++i){
 50             int _x=x+dir[i][0];
 51             int _y=y+dir[i][1];
 52             if(_x<1||_x>n||_y<1||_y>m||dis[_x][_y]!=inf||pic[_x][_y]==‘D‘)continue;
 53             dis[_x][_y]=dis[x][y]+1;
 54             q.push(_x);q.push(_y);
 55         }
 56     }
 57 }
 58
 59 void init(){
 60     state=0;cnt=0;
 61     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
 62         if(pic[i][j]==‘F‘){
 63             xx[cnt]=i;yy[cnt]=j;
 64             state|=(1<<cnt);
 65             ss=cnt;
 66             ++cnt;
 67         }
 68         else if(pic[i][j]==‘G‘){
 69             xx[cnt]=i;yy[cnt]=j;    ///因为‘G‘可过可不过,所以不是绝对条件
 70             ++cnt;
 71         }
 72         else if(pic[i][j]==‘Y‘){
 73             xx[cnt]=i;yy[cnt]=j;
 74             state|=(1<<cnt);
 75             ++cnt;
 76         }
 77     }
 78 }
 79
 80 int check(int en){
 81     int all=1<<cnt;
 82     mst(dp,-1);
 83     dp[1<<ss][ss]=en;
 84     for(int i=1<<ss;i<all;++i){
 85         for(int j=0;j<cnt;++j){
 86             if(!(i&(1<<j))||dp[i][j]<0)continue; ///i状态必须过j,后面操作才有意义
 87             if((i&state)==state)return 1;   ///符合绝对条件,该能量满足
 88             for(int k=0;k<cnt;++k){
 89                 if(j==k||(i&(1<<k)))continue;
 90                 dp[i|(1<<k)][k]=Max(dp[i|(1<<k)][k],dp[i][j]-d[j][k]);
 91                 if(pic[xx[k]][yy[k]]==‘G‘&&dp[i|(1<<k)][k]>=0)
 92                    dp[i|(1<<k)][k]=en;   ///经过‘G‘,能量回满
 93             }
 94         }
 95     }
 96     return 0;
 97 }
 98
 99 int main(){
100     //freopen("lxx.txt","r",stdin);
101     int i,j,x,y,v,group,Case=0;
102     while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
103         mst(d,inf);
104         for(i=1;i<=n;++i)scanf("%s",pic[i]+1);
105         init();
106         for(i=0;i<cnt;++i){
107             mst(dis,inf);
108             bfs(i);
109             for(j=0;j<cnt;++j)
110             d[i][j]=dis[xx[j]][yy[j]];
111         }
112         int l=1,r=4000,ans=inf;
113         while(l<=r){
114             int mid=l+r>>1;
115             if(check(mid)){ans=mid;r=mid-1;}
116             else l=mid+1;
117         }
118         if(ans==inf)printf("-1\n");
119         else printf("%d\n",ans);
120     }
121     return 0;
122 }
时间: 2024-10-13 03:07:47

HDU3681(Prison Break)的相关文章

HDU3681 Prison Break(状压dp)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

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

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3778    Accepted Submission(s): 992 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

hdu 3681 Prison Break(状态压缩+bfs)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

hdu 3681 Prison Break (状态压缩+bfs+最短路)

Prison Break Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3214    Accepted Submission(s): 829 Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But on

hdu 3511 Prison Break

http://acm.hdu.edu.cn/showproblem.php?pid=3511 题意: 给出n个相离或包含的圆,问最里层的圆是第几层 竖着的扫描线与圆在最左侧相切时 1.线在圆的上方或下方无交点,则该圆在第1层 2.线在圆的上下方都有交点,且上下方的交点属于同一个圆C,则该圆在圆C的里面一层 3.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF其中一个在另一个里面,则该圆与在里面的那个圆处在同一层 4.线在圆的上下方都有交点,上方交于圆E,下方交于圆F,EF在同一层,则该圆

【状压+二分+BFS】HDU 3681 Prison Break

通道:http://acm.hdu.edu.cn/showproblem.php?pid=3681 题意:机器人从F出发,走到G可以充电,D不能走进,走到Y关掉开关,要求把所有开关关掉,且电量最少,并求出初始最小电量. 思路:二分初始的电量,预处理任意G,Y,F之间的最短距离,然后状压dp[s][u]:状态为s的u为起点遍历整个图的最小布数. 代码:https://github.com/Mithril0rd/Rojo/blob/master/hdu3681.cpp TAG:代码来自华仔

1254 - Prison Break

  PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Michael Scofield has just broken out of the prison. Now he wants to go to a certain city for his next unfinished job. As you are the only programmer on his gang, he asked yo

HDU 3681 Prison Break floyd+状压+二分

题目链接:点击打开链接 题意: 给定n*m的矩阵: F:起点(有且仅有一个) D:坏点(不能走到这个点) G:能量池(走到这个点可以选择使用这个点的能量池,把电池充满,也可以暂时不用,只能使用一次) Y:目标点 问: 遍历所有Y点需要最小的电池容量是多少. 开始电池满电,每走一步消耗一格电. Y+G的个数<=15. n,m<=15 思路:状压YG,前面几位表示Y,后面几位表示G. 先跑个floyd,然后二分电池容量,状压dp判可行 #include <cstdio> #includ

HDU 3681 Prison Break

/* 给一个n*m的图,F代表起点,G代表充电池,一个充电池只能用一次,但可以用多个充电池,只能把电池充到最大(原始的电量),可以走过不用,D不能走, 问的是把所有的Y走一遍的原始的电量是多少 dp+状态压缩+二分+bfs dp[i][j]表示的状态是在i状态到达j的最大的电量 */ #include<stdio.h> #include<string.h> #include<queue> #define Max(a,b) a>b?a:b #define Min(a