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
*/