hdu 3681(bfs+二分+状压dp判断)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3681

思路:机器人从出发点出发要求走过所有的Y,因为点很少,所以就能想到经典的TSP问题。首先bfs预处理出‘Y',’F','G'之间的最短距离,由于G点可以充电,到达G点就把当前能量更新为电池容量然后继续走。因为每个G点只能充一次电,这就好像TSP中的每个点只能走一次一样,然后就是二分答案了,用状压DP判定当前电池容量的情况下是否能符合条件。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 
  8 struct Node{
  9     int x,y;
 10 }node[17*17];
 11 
 12 int dist[17][17][17][17];
 13 int dp[1<<17][17];
 14 int n,m,state,final_state,start;
 15 char map[17][17];
 16 int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
 17 
 18 void bfs(Node &node)
 19 {
 20     queue<pair<int,int> >que;
 21     que.push(make_pair(node.x,node.y));
 22     dist[node.x][node.y][node.x][node.y]=0;
 23     while(!que.empty()){
 24         int x=que.front().first,y=que.front().second;
 25         que.pop();
 26         for(int i=0;i<4;i++){
 27             int xx=x+dir[i][0],yy=y+dir[i][1];
 28             if(xx>=0&&xx<n&&yy>=0&&yy<m&&map[xx][yy]!='D'){
 29                 if(dist[node.x][node.y][xx][yy]==-1){
 30                     dist[node.x][node.y][xx][yy]=dist[node.x][node.y][x][y]+1;
 31                     que.push(make_pair(xx,yy));
 32                 }
 33             }
 34         }
 35     }
 36 }
 37 
 38 
 39 bool Judge(int Power)
 40 {
 41     memset(dp,-1,sizeof(dp));
 42     dp[(1<<start)][start]=Power;
 43     int res=-1;
 44     for(int i=0;i<(1<<state);i++){
 45         for(int j=0;j<state;j++){
 46             if((i&(1<<j))==0)continue;
 47             if(dp[i][j]<0)continue;
 48             if(((i&final_state)&final_state)==final_state)res=max(res,dp[i][j]);
 49             for(int k=0;k<state;k++){
 50                 if((i&(1<<k))||(j==k))continue;
 51                 if(dist[node[j].x][node[j].y][node[k].x][node[k].y]<0)continue;
 52                 if(dp[i][j]-dist[node[j].x][node[j].y][node[k].x][node[k].y]<0)continue;
 53                 dp[i|(1<<k)][k]=max(dp[i|(1<<k)][k],dp[i][j]-dist[node[j].x][node[j].y][node[k].x][node[k].y]);
 54                 if(map[node[k].x][node[k].y]=='G')dp[i|(1<<k)][k]=Power;
 55             }
 56         }
 57     }
 58     return res>=0;
 59 }
 60 
 61 
 62 int main()
 63 {
 64     int low,high,mid,ans;
 65     while(~scanf("%d%d",&n,&m)){
 66         if(n==0&&m==0)break;
 67         state=0;
 68         final_state=0;
 69         for(int i=0;i<n;i++){
 70             scanf("%s",map[i]);
 71             for(int j=0;j<m;j++){
 72                 if(map[i][j]=='F'){
 73                     start=state;
 74                     node[state].x=i,node[state].y=j;
 75                     final_state|=(1<<state);
 76                     state++;
 77                 }else if(map[i][j]=='G'){
 78                     node[state].x=i,node[state++].y=j;
 79                 }else if(map[i][j]=='Y'){
 80                     node[state].x=i,node[state].y=j;
 81                     final_state|=(1<<state);
 82                     state++;
 83                 }
 84             }
 85         }
 86         memset(dist,-1,sizeof(dist));
 87         for(int i=0;i<state;i++){
 88             bfs(node[i]);
 89         }
 90         low=0,high=300,ans=-1;
 91         while(low<=high){
 92             mid=(low+high)>>1;
 93             if(Judge(mid)){
 94                 ans=mid;
 95                 high=mid-1;
 96             }else
 97                 low=mid+1;
 98         }
 99         printf("%d\n",ans);
100     }
101     return 0;
102 }
103 
104 
105         
106 
107                     
View Code

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值