首页 > 代码库 > hdu3681(状压dp)

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 }
View Code

 

hdu3681(状压dp)