uva 1601 The Morning after Halloween

题意:

一张图,有空格,有障碍,有字母

每秒钟每个字母可以移动到相邻非障碍格

问所有的小写字母移动到大写字母所需的最少时间

https://vjudge.net/problem/UVA-1601

预处理每个状态有哪些后继状态

#include<queue>
#include<cstdio>
#include<cstring> 
#include<iostream>
using namespace std;
int m,n,p,s[3],t[3];
int dx[5]={0,-1,0,1,0},dy[5]={0,0,1,0,-1};
int id[17][17],cnt,x[200],y[200],can[200][7];
int dis[200][200][200];
bool a[17][17];
string ss;
struct node
{
    int a,b,c;
    bool operator == (node q) const
    {
        return a==q.a && b==q.b && c==q.c;
    }
}now,nxt;
queue<node>q;
void init()
{
    cnt=0;
    memset(a,false,sizeof(a));
    for(int i=1;i<=n;i++)
    {
        getline(cin,ss);
        for(int j=0;j<m;j++)
        {
            if(ss[j]!='#') x[++cnt]=i,y[cnt]=j+1,id[i][j+1]=cnt;
            else a[i][j+1]=true;
            if(islower(ss[j])) s[ss[j]-'a']=cnt;
            else if(isupper(ss[j])) t[ss[j]-'A']=cnt;
        }
    } 
} 
void pre()
{
    memset(can,0,sizeof(can));
    int nx,ny;
    for(int i=1;i<=cnt;i++)
     for(int j=0;j<5;j++)
     {
         nx=x[i]+dx[j]; ny=y[i]+dy[j];
         if(nx<1 || nx>n || ny<1 || ny>m || a[nx][ny]) continue;
         can[i][++can[i][0]]=id[nx][ny];
     }
    if(p<=2) can[++cnt][++can[cnt][0]]=cnt,s[2]=t[2]=cnt;
    if(p<=1) can[++cnt][++can[cnt][0]]=cnt,s[1]=t[1]=cnt;
}
void solve()
{
    while(!q.empty()) q.pop();
    memset(dis,-1,sizeof(dis));
    node last;
    last.a=t[0]; last.b=t[1]; last.c=t[2];
    dis[s[0]][s[1]][s[2]]=0; 
    now.a=s[0]; now.b=s[1]; now.c=s[2];
    if(now==last) { printf("0
"); return; }
    q.push(now);
    int na,nb,nc;
    while(!q.empty())
    {
        now=q.front(); q.pop();
        na=now.a; nb=now.b; nc=now.c;
        for(int i=1;i<=can[na][0];i++)
        {
            for(int j=1;j<=can[nb][0];j++)
            {
                if(can[na][i]==can[nb][j]) continue;
                if(na==can[nb][j] && nb==can[na][i]) continue;
                for(int k=1;k<=can[nc][0];k++)
                {
                    if(can[na][i]==can[nc][k] || can[nb][j]==can[nc][k]) continue;
                    if(na==can[nc][k] && nc==can[na][i] || nb==can[nc][k] && nc==can[nb][j]) continue;
                    if(dis[can[na][i]][can[nb][j]][can[nc][k]]!=-1) continue;
                    nxt.a=can[na][i]; nxt.b=can[nb][j]; nxt.c=can[nc][k];
                    if(nxt==last) { 
                    printf("%d
",dis[na][nb][nc]+1); return; }
                    dis[nxt.a][nxt.b][nxt.c]=dis[na][nb][nc]+1;
                    q.push(nxt);
                }
            }
        }
    }
} 
int main()
{
    char y;
    while(scanf("%d%d%d",&m,&n,&p)!=EOF)
    {
        if(!m) return 0;
        y=getchar();
        init();
        pre();
        solve();
    } 
} 
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7281322.html