Codeforces Testing Round #9 D/386D

给你一张完全图,每条边有一种颜色,有三个石头,能把一个石头从一个点a移动到b的条件是:1、没有石头在b上。2、a,b边的颜色和另两块石头所在点连边的颜色相同。现在要把这三个石头移动到1,2,3号点,问最少移动多少步?


思路:这道题目看起来有点复杂,仔细想想这就是一个最短路问题(三维最短路),也可以理解为一种图上的dp,用用三元组(i,j,k)第一块石头在i点,第二个在j,第三个在k的状态,状态总数为70*70*70,然后d[i][j][k]表示把三个石头从初始状态移动到状态(i,j,k)时所需要的最少步数,也可以理解为这个三维图上的距离。写的时候按照dijkstra算法去写就可以了,向外拓展时注意判定条件,更新时需要维护路径。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<iostream>
#define INF 1<<30
using namespace std;
struct node
{
    int x,y,z,d;
    bool operator <(const node &rhs)const
    {
        return d>rhs.d;
    }
}fa[80][80][80];
struct NODE
{
    int from,to;
};
char s[80][80];int n,d[80][80][80];
bool done[80][80][80];
priority_queue<node>q;
node makenode(int x,int y,int z,int d)
{
    node res;
    res.x=x;res.y=y;res.z=z;res.d=d;
    return res;
}
void dij(int s1,int s2,int s3)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                d[i][j][k]=INF;
    d[s1][s2][s3]=0;
    memset(done,0,sizeof(done));
    node tmp;tmp.x=s1;tmp.y=s2;tmp.z=s3;tmp.d=0;q.push(tmp);
    while(!q.empty())
    {
        tmp=q.top();
        q.pop();
        int x=tmp.x,y=tmp.y,z=tmp.z,D=tmp.d;
        if(done[x][y][z])
            continue;
        done[x][y][z]=1;
        for(int i=1;i<=n;i++)
            if(i!=y&&i!=x&&i!=z)
        {
            node u;
            if(s[x][i]==s[y][z]&&D+1<d[i][y][z])
            {
                fa[i][y][z]=tmp;
                d[i][y][z]=D+1;
                u=makenode(i,y,z,D+1);
                q.push(u);
            }
            if(s[y][i]==s[x][z]&&D+1<d[x][i][z])
            {
                fa[x][i][z]=tmp;
                d[x][i][z]=D+1;
                u=makenode(x,i,z,D+1);
                q.push(u);
            }
            if(s[z][i]==s[x][y]&&D+1<d[x][y][i])
            {
                fa[x][y][i]=tmp;
                d[x][y][i]=D+1;
                u=makenode(x,y,i,D+1);
                q.push(u);
            }
        }
    }
}
NODE makeNODE(int fx,int fy,int fz,int x,int y,int z)
{
    NODE res;
    if(fx!=x)
        res.from=fx,res.to=x;
    if(fy!=y)
        res.from=fy,res.to=y;
    if(fz!=z)
        res.from=fz,res.to=z;
    return res;
}
int main()
{
    scanf("%d",&n);
    int x,y,z;
    scanf("%d%d%d",&x,&y,&z);
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    dij(x,y,z);
    int ans=INF,u,v,w;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            for(int k=1;k<=3;k++)
                if(i!=j&&i!=k&&j!=k)
                    if(ans>d[i][j][k])
                        ans=d[i][j][k],u=i,v=j,w=k;
    if(ans<INF)
    {
        printf("%d\n",ans);
        stack<NODE>stk;
        while(x!=u||y!=v||z!=w)
        {
            NODE tmp=makeNODE(fa[u][v][w].x,fa[u][v][w].y,fa[u][v][w].z,u,v,w);
            int nx=fa[u][v][w].x;
            int ny=fa[u][v][w].y;
            int nz=fa[u][v][w].z;
            u=nx,v=ny,w=nz;
            stk.push(tmp);
        }
        while(!stk.empty())
        {
            NODE tmp=stk.top();
            printf("%d %d\n",tmp.from,tmp.to);
            stk.pop();
        }
    }
    else printf("-1");
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值