题目:click
题意:给定一个n*m的地图,D表示不能走的地方,G补充满能量,问从F点走完所有的Y点最小的能量,走一个消耗一格能量。
注意一下题目中所给的范围,Y+G的数量不超过15。在无数条路径中找出一条最佳路径,D是不能走的,所需点的数量顶多16个(加上了F点),其实可以发现本质就是一个TSP的变形问题,所需要的点也就这三个。bfs处理出每两个点的最短距离,建立一个新的图。
之后直接状压dp,但是我们需要注意状态的的属性问题,取最大还是最小值进行状态转移?取max有可能将最小路径的值覆盖,取min可能不能确保是这条路上的max。二分答案即可。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e7+5;
int mo[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int n,m,state,fvis;
bool vis[20][20];
int mp[20][20];
int dp[20][(1<<18)];
int cnt=0;
struct A{
int x,y;
}a[20];
struct B{
int x,y;
int di;
};
int dis[20][20];
void bfs(int t1,int t2)
{
memset(vis,false,sizeof(vis));
queue<B>hh;
B temp;
temp.di=0;
temp.x=a[t1].x;
temp.y=a[t1].y;
hh.push(temp);
while(!hh.empty())
{
temp=hh.front();
for(int i=0;i<4;i++)
{
B tmp;
tmp.x=temp.x+mo[i][0];
tmp.y=temp.y+mo[i][1];
if(tmp.x<0||tmp.x>n-1||tmp.y<0||tmp.y>m-1||vis[tmp.x][tmp.y]||mp[tmp.x][tmp.y]=='D')
continue;
vis[tmp.x][tmp.y]=true;
tmp.di=temp.di+1;
if(tmp.x==a[t2].x&&tmp.y==a[t2].y)
{
dis[t1][t2]=tmp.di;
dis[t2][t1]=tmp.di;
return ;
}
hh.push(tmp);
}
hh.pop();
}
}
bool check(int res)
{
int i,j,k;
int yyyy=(1<<cnt);
memset(dp,-1,sizeof(dp));
dp[fvis][(1<<fvis)]=res;
for(i=0;i<yyyy;i++)
{
for(j=0;j<cnt;j++)
{
if(dp[j][i]==-1||((1<<j)&i)==0)
continue;
if((state&i)==state&&dp[j][i]!=-1)
return true;
for(k=0;k<cnt;k++)
{
if(dis[j][k]==inf||((1<<k)&i)||k==j)
continue;
if(dp[j][i]-dis[j][k]<0)
{
continue;
}
int temp=i|(1<<k);
if(mp[a[k].x][a[k].y]=='G')
{
dp[k][temp]=res;
continue;
}
dp[k][temp]=max(dp[k][temp],dp[j][i]-dis[j][k]);
}
}
}
return false;
}
int main()
{
while(~scanf("%d %d",&n,&m)&&(n||m))
{
getchar();
state=0;
int i,j,k;
cnt=0;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%c",&mp[i][j]);
if(mp[i][j]=='F'||mp[i][j]=='G'||mp[i][j]=='Y')
{
if(mp[i][j]=='F')
fvis=cnt;
if(mp[i][j]=='F'||mp[i][j]=='Y')
state+=(1<<cnt);
a[cnt].x=i;
a[cnt++].y=j;
continue;
}
}
getchar();
}
memset(dis,inf,sizeof(dis));
for(i=0;i<cnt;i++)
{
for(j=0;j<cnt;j++)
{
if(i==j)
dis[i][j]=0;
else
bfs(i,j);
}
}
int ans=-1;
int l=0,r=250;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d\n",ans);
}
return 0;
}