hdu3681(状压dp)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu3681(状压dp)相关的知识,希望对你有一定的参考价值。
题意:给你一个n*m的矩阵,‘F‘是起点。机器人从F出发,走到G可以充电(也可以选择不充,同一个G只能充一次电),走到Y关掉开关,D不能走进,每走一步路(上下左右一格)需要消耗1点电量
要求把所有开关关掉,且机器人电量上限最少,并求出该最小电量上限。 充电器数量+开关数量<=15,n,m<=15;
解法:首先我们把充电器和开关当做节点,用bfs求出每个节点之间的距离,然后二分电量,状压dp求解判别式
一开始因为忘记了两个节点之间会存在无法到达的情况,WA了几发,qaq
1 #include<string> 2 #include<cstring> 3 #include<cstdio> 4 #include<iostream> 5 #include<vector> 6 #include<cmath> 7 #include<algorithm> 8 #include<queue> 9 using namespace std; 10 typedef long long ll; 11 const ll mod=1e9+7; 12 char map[20][20]; 13 typedef struct node 14 { 15 int x,y,state; 16 }node ; 17 node arr[20]; 18 int cnt=0,n,m,sx,sy; 19 int dp[17][(1<<18)+998]; 20 int vis[20][20],dis[20][20]; 21 int aim; 22 const int dx[4]={0,0,1,-1}; 23 const int dy[4]={1,-1,0,0}; 24 bool isok(int x,int y) 25 { 26 if(x<0||y<0||x>=n||y>=m)return false ; 27 if(vis[x][y]!=-1||map[x][y]==‘D‘)return false ; 28 return true; 29 } 30 int getdis(int a) 31 { 32 memset(vis,-1,sizeof(vis)); 33 queue<node>dui; 34 node now; 35 now.x=arr[a].x,now.y=arr[a].y; 36 vis[now.x][now.y]=0; 37 dui.push(now); 38 while(!dui.empty()) 39 { 40 now=dui.front(); 41 dui.pop(); 42 int x=now.x,y=now.y,step=vis[x][y]; 43 for(int i=0;i<4;i++) 44 { 45 int xx=x+dx[i],yy=y+dy[i]; 46 if(isok(xx,yy)) 47 { 48 vis[xx][yy]=step+1; 49 node tmp; 50 tmp.x=xx,tmp.y=yy; 51 dui.push(tmp); 52 } 53 } 54 } 55 for(int i=0;i<cnt;i++)dis[a][i]=dis[i][a]=vis[arr[i].x][arr[i].y]; 56 } 57 bool check(int lim) 58 { 59 int i,j; 60 memset(dp,-1,sizeof(dp)); 61 dp[0][1]=lim; 62 for(i=1;i<(1<<cnt);i++) 63 { 64 for(j=0;j<cnt;j++) 65 { 66 if(i&(1<<j)==0)continue; 67 if(dp[j][i]==-1)continue; 68 if((i|aim)==i) 69 { 70 //printf("j:%d state:%d dp:%d\n",j,i,dp[j][i]); 71 return true; 72 } 73 if(dp[j][i]==0)continue; 74 for(int k=0;k<cnt;k++) 75 { 76 if(i&(1<<k))continue; 77 int dist=dis[j][k]; 78 if(dist==-1)continue; 79 //if(lim<=3)printf("j:%d k:%d dis:%d\n",j,k,dis[j][k]); 80 if(dist>dp[j][i])continue; 81 dp[k][i|(1<<k)]=max(dp[k][i|(1<<k)],dp[j][i]-dist); 82 if(arr[k].state==1)dp[k][i|(1<<k)]=lim; 83 //printf("newstate:%d\n",i|(1<<k)); 84 } 85 } 86 } 87 //printf("lim:%d false \n",lim); 88 return false ; 89 } 90 void init() 91 { 92 int i,j; 93 cnt=0; 94 for(i=0;i<n;i++) 95 { 96 for(j=0;j<m;j++) 97 { 98 if(map[i][j]==‘F‘) 99 { 100 arr[0].x=i; 101 arr[0].y=j; 102 arr[0].state=0; 103 } 104 else if(map[i][j]==‘G‘) 105 { 106 cnt++; 107 arr[cnt].x=i; 108 arr[cnt].y=j; 109 arr[cnt].state=1; 110 } 111 else if(map[i][j]==‘Y‘) 112 { 113 cnt++; 114 arr[cnt].x=i; 115 arr[cnt].y=j; 116 arr[cnt].state=2; 117 //printf("matter:%d\n",cnt); 118 } 119 } 120 } 121 cnt++; 122 for(i=0;i<cnt;i++)getdis(i); 123 aim=0; 124 for(i=0;i<cnt;i++) 125 { 126 if(arr[i].state==2) 127 { 128 aim|=(1<<i); 129 } 130 } 131 } 132 int main() 133 { 134 int i,j; 135 while(scanf("%d%d",&n,&m)!=EOF) 136 { 137 if(!n&&!m)return 0; 138 for(i=0;i<n;i++)scanf("%s",map[i]); 139 init(); 140 int l=0,r=20000; 141 if(!check(r)) 142 { 143 printf("-1\n"); 144 continue; 145 } 146 while(r-l>1) 147 { 148 int mid=(l+r)/2; 149 if(check(mid))r=mid; 150 else l=mid; 151 } 152 int ans=l; 153 if(!check(l))ans++; 154 printf("%d\n",ans); 155 } 156 }
以上是关于hdu3681(状压dp)的主要内容,如果未能解决你的问题,请参考以下文章