解题思路:这道题属于图上来回走的问题,可以把重复走的过程弱化,即只强调从u->v的结果,中间经过的节点都不考虑。这道题里面'G','F','Y'是重要的节点,其余的点我们是可以忽略的,也就是说,假设从u->v,我们只需要知道最短路径是多少就可以了,至于是怎么走的,中间绕过了多少个'D'都不是我们关心的。这样我们就只需要用bfs找到'G','F','Y'两两之间的最短路径,剩下的就是一个典型的TSP问题了。对于最小的电池量,可以二分答案,这里很容易想到。在dfs中,我们同样只要知道两点之间的最短路径就可以了,并不需要知道如何走过来的,此外,由于每个'Y'都必须要走到,且数据量较小,所以可以用状态压缩。
对于这种图上来回走的问题,可以把重复走的过程弱化,只强调走的结果。
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
struct edge
{
int to,next;
}e[2000];
struct node
{
int vid,step;
};
char mp[20][20];
int id[20][20],c[20][2],head[300],dis[20][20];
int cnt,obj,ids,mid,m,n;
bool mk[20];
void init()
{
memset(id,-1,sizeof(id));
memset(dis,-1,sizeof(dis));
memset(head,-1,sizeof(head));
cnt=0;ids=1;obj=0;
}
void add(int x,int y)
{
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
void bfs(int x)
{
int u,v;
node djw,cur,next;
queue<node> q;
bool vis[400];
memset(vis,0,sizeof(vis));
djw.vid=x;
djw.step=0;
q.push(djw);
vis[x]=true;
while(!q.empty())
{
cur=q.front();
q.pop();
u=cur.vid;
if(id[u/m][u%m]!=-1)
dis[id[x/m][x%m]][id[u/m][u%m]]=cur.step;
for(int i=head[u];i!=-1;i=e[i].next)
{
v=e[i].to;
if(!vis[v])
{
vis[v]=true;
next.vid=v;
next.step=cur.step+1;
q.push(next);
}
}
}
}
int dfs(int bag,int pos,int sta)
{
if((sta&obj)==obj) return 1;
for(int i=0;i<ids;i++)
{
if(mk[i] || dis[pos][i]==-1) continue;
if(dis[pos][i]<=bag)
{
if(mp[c[i][0]][c[i][1]]=='G')
{
mk[i]=true;
if(dfs(mid,i,sta|(1<<i))) return 1;
mk[i]=false;
}
else
{
mk[i]=true;
if(dfs(bag-dis[pos][i],i,sta|(1<<i))) return 1;
mk[i]=false;
}
}
}
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0 && m==0)
break;
init();
for(int i=0;i<n;i++)
scanf("%s",mp[i]);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]=='D') continue;
if(mp[i][j]=='F')
{
c[0][0]=i;
c[0][1]=j;
id[i][j]=0;
}
else if(mp[i][j]=='G')
{
c[ids][0]=i;
c[ids][1]=j;
id[i][j]=ids++;
}
else if(mp[i][j]=='Y')
{
c[ids][0]=i;
c[ids][1]=j;
obj|=(1<<ids);
id[i][j]=ids++;
}
if(i-1>=0 && mp[i-1][j]!='D')
add(i*m+j,(i-1)*m+j);
if(i+1<n && mp[i+1][j]!='D')
add(i*m+j,(i+1)*m+j);
if(j-1>=0 && mp[i][j-1]!='D')
add(i*m+j,i*m+j-1);
if(j+1<m && mp[i][j+1]!='D')
add(i*m+j,i*m+j+1);
}
}
for(int i=0;i<ids;i++)
bfs(c[i][0]*m+c[i][1]);
int flag=1;
for(int i=1;i<ids;i++)
{
if(mp[c[i][0]][c[i][1]]=='Y' && dis[0][i]==-1)
{
flag=0;
break;
}
}
int ans=-1;
if(flag)
{
int l=0,r=n*m*(ids-1);
while(l<=r)
{
mid=(l+r)>>1;
memset(mk,0,sizeof(mk));
mk[0]=true;
if(dfs(mid,0,1))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
}
printf("%d\n",ans);
}
return 0;
}