2017.8.27 魔法王国

魔法王国

【问题描述】
  从古代开始,魔法王国就有一个由双向魔法门构成的网络。每一个魔法门以魔法连接一对城市,允许他们进行魔法交流和旅行。被魔法门连接起来的城市被称为相邻的。
  Albert王子和Betty公主住在相邻的城市。所以,在他们的孩提时代,Albert和Betty经常通过魔法通讯球保持联系,魔法通讯球是通过连接城市的魔法门工作的。
  Albert和Betty相爱了。他们爱得如此深以至不能在没有对方时生活一分钟。他们总是把魔法球带在身边,从而,他们可以在任何时候与对方说话。他们的爱情有一个奇怪的事情——他们从没见过对方,甚至他们害怕同时在同一个城市。人们说,是魔法球影响了他们。
  对于Albert和Betty来说,在王国里旅行是一件复杂的事情。他们必须通过魔法门旅行,这对于皇家而言也是非常昂贵的。他们可以同时使用不同的魔法门移动到不同的城市,也可以一方使用魔法门移动到一个城市,另一方呆在一个城市。在任何时候他们必须在相邻的城市。他们不能同时使用同一个魔法门移动。
  须找到一个最便宜的方案——他们通过魔法门移动的次数最少。如果他们同时使用魔法门,计做两次移动。

【输入格式】
  输入文件的第一行包含整数n,m,a1,b1,a2,b2。这里n(3 <= n <=100)是王国里的城市数(城市从1到n标号);m(2 <= m <= 1000)是魔法门的个数;是相邻的城市,对应的分别是Albert和Betty的出发城市;也是相邻的城市,对应的分别是Albert和Betty希望到达的城市。
接下来的m行描述魔法门。每一行包含两个数pi1和pi2——用魔法门相连的城市。任意两个城市之间最多只有一个魔法门连接。

【输出格式】
  输出文件的第一行包含两个用一个空格隔开的整数c。这里c是方案中最少的移动次数;

【输入样例】KINGDOM.IN
4 5 1 2 2 1
1 2
2 3
3 4
4 1
1 3

【输出样例】KINGDOM.OUT
3


【分析】
  大家看完题目,就会发现这是一道最短路问题。但是,题目中最短路的起点和终点是一对城市,而且他们在旅行的过程中,两人也必须在相邻的城市。如果直接跑一遍最短路是肯定不行的。仔细分析题目,发现他们经过的城市都是相邻的。这样我们可以把每对相邻的城市都看作一个点,这样共有2m个点。接下来要确定每两点之间的距离,有3种情况:
1. 这两对相邻城市中,第一个城市相同,第二个城市联通,边权为1;
2. 这两对相邻城市中,第二个城市相同,第一个城市联通,边权为1;
3. 这两对相邻城市中,两个城市都联通,边权为2;
  做完这些之后,跑一遍最短路即可。


本人略丑的代码<-_->

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#define For(c,a,b) for(int c=a;c<=b;c++)
#define foR(c,a,b) for(int c=a;c>=b;c--)
using namespace std;
const int N=405;
int n,m,a1,a2,b1,b2,x[N],y[N];
int f[N][N],g[N][N],tot;
int main()
{
    freopen("kingdom.in","r",stdin);
    freopen("kingdom.out","w",stdout);
    scanf("%d%d%d%d%d%d",&n,&m,&a1,&a2,&b1,&b2);
    For(i,1,m)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        g[u][v]=++tot; x[tot]=u; y[tot]=v;
        g[v][u]=++tot; x[tot]=v; y[tot]=u;
    }
    memset(f,0x3f,sizeof(f));
    For(i,1,tot-1) For(j,i+1,tot)
    {
        if (x[i]==x[j]&&g[y[i]][y[j]]) f[i][j]=1;
        else if (y[i]==y[j]&&g[x[i]][x[j]]) f[i][j]=1;
        else if (g[x[i]][x[j]]&&g[y[i]][y[j]]
        &&(x[i]!=y[j]||x[j]!=y[i])) f[i][j]=2;
        f[j][i]=f[i][j];
    }
    For(k,1,tot) For(i,1,tot)
    if (k!=i) For(j,1,tot)
    if (k!=j&&i!=j)
    f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
    //Floyed可能会超时,可能是数据水
    //建议用时间复杂度低于O(m^2)的算法
    printf("%d\n",f[g[a1][a2]][g[b1][b2]]);
    fclose(stdin); fclose(stdout);
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值