[关键字]:搜索+建图
[题目大意]:给出一个矩阵,矩阵里有5种格子:‘F’初始位置;‘G’:能量池——可以将能量补满;‘Y’开关;‘D’:不能走到;‘S’:空地,问最小拥有多少初始能量才能走过所有开关。
//============================================================================================================================================
[分析]:首先只要有解,中间走过哪些‘S’都无所谓,只有‘Y’和‘G’是需要考虑的节点,所以可以先BFS或Floyd求出所有‘Y’‘G’两两之间的最短路,然后构建一个新图,以‘F’‘Y’‘G’为点连边。然后二分答案,在这个图上DFS不走超过二分的答案的边判断当前答案下能否走到所有‘Y’。因为可以选择先用哪个‘G’(先用就先到),所以不用考虑走过而不使‘G’的情况。
[代码]:
View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
const int INF=10000;
struct node
{
int x,y;
}point,S;
int N,M,tot,ans,now;
int dis[16][16][16][16],c[36][36];
char map[30][30];
bool goal;
vector<node> stata;
vector<node> energy;
node Find(int k)
{
if (k==1) return S; else
if (k<=energy.size()+1) return energy[k-2]; else
return stata[k-energy.size()-2];
}
int d(int i,int j)
{
node x=Find(i),y=Find(j);
return dis[x.x][x.y][y.x][y.y];
}
void Init()
{
for (int i=0;i<N;i++) scanf("%s",map[i]);
energy.clear();
stata.clear();
for (int i1=0;i1<N;i1++)
for (int j1=0;j1<M;j1++)
for (int i2=0;i2<N;i2++)
for (int j2=0;j2<M;j2++)
if (i1==i2 && j1==j2) dis[i1][j1][i2][j2]=0;
else dis[i1][j1][i2][j2]=INF;
for (int i=0;i<N;i++)
for (int j=0;j<M;j++)
if (map[i][j]!='D')
for (int k=0;k<4;k++)
{
int xx=i+dx[k],yy=j+dy[k];
if (0<=xx && xx<N && 0<=yy && yy<M && map[xx][yy]!='D')
dis[i][j][xx][yy]=1;
}
for (int i1=0;i1<N;i1++)
for (int j1=0;j1<M;j1++)
for (int i2=0;i2<N;i2++)
for (int j2=0;j2<M;j2++)
for (int i3=0;i3<N;i3++)
for (int j3=0;j3<M;j3++)
if (dis[i2][j2][i3][j3]>dis[i2][j2][i1][j1]+dis[i1][j1][i3][j3])
dis[i2][j2][i3][j3]=dis[i2][j2][i1][j1]+dis[i1][j1][i3][j3];
for (int i=0;i<N;i++)
for (int j=0;j<M;j++)
{
point.x=i,point.y=j;
if (map[i][j]=='F') S.x=i,S.y=j;
else if (map[i][j]=='Y') stata.push_back(point);
else if (map[i][j]=='G') energy.push_back(point);
}
tot=energy.size()+stata.size()+1;
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
c[i][j]=d(i,j);
}
void DFS(int s,int l,int g,int maxl)
{
if (l>=now || maxl>= now) return;
if (g>=ans)
{
goal=1;
now=maxl;
return;
}
for (int i=1;i<=tot;i++)
if ((g&(1<<(i-1)))==0)
{
if (l+c[s][i]>=now) continue;
if (i<=energy.size()+1) DFS(i,0,g+(1<<(i-1)),max(maxl,l+c[s][i]));
else DFS(i,l+c[s][i],g+(1<<(i-1)),max(maxl,l+c[s][i]));
}
}
int Solve()
{
for (int i=energy.size()+2;i<=tot;i++)
if (c[i][1]>=INF) return -1;
ans=1;
for (int i=1;i<=stata.size();i++)
ans+=1<<(i+energy.size());
//printf("%d\n",ans);
goal=0;
for (int i=1;i<=N*M;i++)
{
now=i;
DFS(1,0,1,0);
if (goal) return now;
}
}
int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
while (scanf("%d%d",&N,&M))
{
if (!N && !M) break;
Init();
printf("%d\n",Solve());
}
return 0;
}