2010杭州赛区的题目
题意:
机器人从F出发,走到G可以充电,走到Y关掉开关,D不能走进,要求把所有开关关掉,且电量最少,并求出该最小电量。
题解:
像这种题目暂时找不到很好的解决方法,可以试着想想暴力的方法,就是枚举每个电量是否满足,一般这样的枚举都是用二分,对于判断是否满足条件可以用状压dp来解决。我们首先要预处理出充电地点和发电站两两之间的最短路径可以用bfs解决,然后将这些点压缩TSP问题。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; typedef long long lld; const int oo=0x3f3f3f3f; const lld OO=1LL<<61; const int Mod=1000000007; int dis[20][20][20][20]; int n,m,full,cnt; int tagS;//目标状态 关掉所有发电机的状态 int dp[(1<<16)+5][20]; char maze[20][20]; int start; struct POINT { int x,y; }po[20]; int d[4][2]={ {1,0},{-1,0},{0,1},{0,-1} }; void intput() { tagS=cnt=0; for(int i=1;i<=n;i++) { getchar(); for(int j=1;j<=m;j++) { maze[i][j]=getchar(); if(maze[i][j]=='Y'||maze[i][j]=='F') { if(maze[i][j]=='F') start=cnt; tagS|=(1<<cnt); po[cnt].x=i; po[cnt].y=j; cnt++; } else if(maze[i][j]=='G') { po[cnt].x=i; po[cnt].y=j; cnt++; } } } } void bfs(int sx,int sy) { POINT q[300],next,now; int front,rear; front=rear=0; now.x=sx; now.y=sy; q[rear++]=now; dis[sx][sy][sx][sy]=0; while(front<rear) { now=q[front++]; for(int k=0;k<4;k++) { next.x=now.x+d[k][0]; next.y=now.y+d[k][1]; if(next.x>=1&&next.x<=n&&next.y>=1&&next.y<=m) { if(maze[next.x][next.y]!='D') { if(dis[sx][sy][next.x][next.y]==-1) { dis[sx][sy][next.x][next.y]=dis[sx][sy][now.x][now.y]+1; q[rear++]=next; } } } } } } bool judge(int V) { full=(1<<cnt)-1; int res=-1; memset(dp,-1,sizeof dp); dp[1<<start][start]=V; for(int s=0;s<=full;s++) { for(int i=0;i<cnt;i++) { if(dp[s][i]==-1)continue; if(!(s&(1<<i)))continue; if(((s&tagS)&tagS)==tagS)//如果发电站都关闭了 res=max(res,dp[s][i]); for(int j=0;j<cnt;j++) { if(s&(1<<j))continue; if(i==j)continue; int temp=dis[po[i].x][po[i].y][po[j].x][po[j].y]; if(temp==-1)continue; temp=dp[s][i]-temp; if(temp<0)continue; int st=s|(1<<j); dp[st][j]=max(dp[st][j],temp); if(maze[po[j].x][po[j].y]=='G')dp[st][j]=V; } } } return res>=0; } void solve() { memset(dis,-1,sizeof dis); for(int i=0;i<cnt;i++) bfs(po[i].x,po[i].y); int l=0,r=300,mid; while(l<=r) { mid=(l+r)>>1; if(judge(mid)) r=mid-1; else l=mid+1; } if(l==301)l=-1; printf("%d\n",l); } int main() { while(scanf("%d %d",&n,&m)!=EOF) { if(n==0&&m==0)break; intput(); solve(); } return 0; } /** 5 5 GDDSS SSSFS SYGYS SGSYS SSYSS 0 0 */