今天突然想做道题, 区域赛的题对于我来讲还是不简单的。。。 代码一多 写的看起来就挫了。。。
看网上说是状态压缩DP,看了下数据,Y+G小于等于15 好吧,看来确实是这样,一开始还在想难道可以用搜索?
状态压缩DP一直习惯于从通过前面的状态来更新当前状态,写的有些混乱。。。 下次试试从当前状态更新到下一个状态。。。
把所有的Y点和G点编号,求出各个点之间的距离,如果Y点某点与起点不连通,说明无解,否则有解 DP 遇到G则步数变为0,参考别人是用二分查找求解的 我也就这么做了。。。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int INF=1<<29;
int as[600000];
void st()
{
int i, k=0;
for(i=1; i<600000; i*=2)
{
as[i]=++k;
}
}
struct Node
{
int x, y;
} nod[17];
struct POS
{
POS() {}
POS(int a,int b,int c)
{
x=a,y=b,now=c;
}
int x, y, now;
} pos;
int n, m, p, q, sx, sy;
int dis[17][17], dp[600000][17], the[17][17], num, ll;
char map[17][17];
bool ans;
void init()
{
int i, j;
memset(the,-1,sizeof(the));
p=1;
for(i=0; i<n; i++)
{
for(j=0; j<m; j++)
{
if(map[i][j]=='F')
sx=i, sy=j;
if(map[i][j]=='Y')
{
nod[p].x=i, nod[p].y=j;
the[i][j]=p;
p++;
}
}
}
q=p;
for(i=0; i<n; i++)
for(j=0; j<m; j++)
{
if(map[i][j]=='G')
{
nod[q].x=i, nod[q].y=j;
the[i][j]=q;
q++;
}
}
nod[0].x=sx, nod[0].y=sy;
the[sx][sy]=0;
for(i=0; i<q; i++)
for(j=0; j<q; j++)
{
if(i==j)
dis[i][j]=0;
else dis[i][j]=INF;
}
}
int dx[]= {1,0,-1,0};
int dy[]= {0,1,0,-1};
bool can(int x,int y)
{
if(x<0||x>=n||y<0||y>=m||map[x][y]=='D')
return false;
return true;
}
void bfs()
{
int i, j, nx, ny, x, y, now;
POS tmp;
bool vis[17][17];
for(i=0; i<q; i++)
{
memset(vis,0,sizeof(vis));
queue<POS> qq;
qq.push(POS(nod[i].x,nod[i].y,0));
while(!qq.empty())
{
tmp=qq.front();
qq.pop();
x=tmp.x, y=tmp.y, now=tmp.now;
for(j=0; j<4; j++)
{
nx=x+dx[j], ny=y+dy[j];
if(can(nx,ny)&&!vis[nx][ny])
{
if(the[nx][ny]!=-1)
dis[i][the[nx][ny]]=now+1;
vis[nx][ny]=true;
qq.push(POS(nx,ny,now+1));
}
}
}
}
for(i=0; i<p; i++)
for(j=0; j<p; j++)
if(dis[i][j]==INF) ans=false;
}
bool deal(int maxt)
{
int i, j, k, tmp;
bool f=false;
for(i=0; i<num; i++)
for(j=0; j<q; j++)
dp[i][j]=INF;
dp[0][0]=0;
int ed;
for(i=1; i<num; i++)
{
for(j=i; j>0; j-=j&(-j))
{
tmp=j&(-j);
ed=as[tmp];
for(k=0; k<q; k++)
if(dp[i^tmp][k]+dis[k][ed]<=maxt)
dp[i][ed]=min(dp[i^tmp][k]+dis[k][ed],dp[i][ed]);
if(ed>=p&&dp[i][ed]!=INF)
dp[i][ed]=0;
if(dp[i][ed]!=INF)
{
for(k=0; k<p; k++)
{
if(dp[i][ed]+dis[ed][k]<=maxt)
dp[i|(1<<(k-1))][k]=min(dp[i|(1<<(k-1))][k],dp[i][ed]+dis[ed][k]);
}
for(; k<q; k++)
{
if((1<<(k-1))&i) continue;
if(dp[i][ed]+dis[ed][k]<=maxt)
dp[i|(1<<(k-1))][k]=0;
}
}
}
if(i%ll==ll-1)
{
for(j=0; j<q; j++)
if(dp[i][j]<=maxt) f=true;
}
}
return f;
}
int main()
{
int i, j, tmp, l, r;
st();
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
for(i=0; i<n; i++)
scanf("%s",map[i]);
init();
ans=true;
bfs();
num=1<<(q-1);
l=1, r=300;
ll=1<<(p-1);
if(ans)
{
while(l<r)
{
m=(l+r)>>1;
if(deal(m))
r=m;
else l=m+1;
}
}
if(ans) printf("%d\n",r);
else puts("-1");
}
return 0;
}