07-图4 哈利·波特的考试(Folyd算法,Dijkstra算法)

07-图4 哈利·波特的考试

分数 25

作者 陈越

单位 浙江大学

哈利·波特要考试了,他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念,例如ahah可以将老鼠变成猫。另外,如果想把猫变成鱼,可以通过念一个直接魔咒lalala,也可以将猫变老鼠、老鼠变鱼的魔咒连起来念:hahahehe。

现在哈利·波特的手里有一本教材,里面列出了所有的变形魔咒和能变的动物。老师允许他自己带一只动物去考场,要考察他把这只动物变成任意一只指定动物的本事。于是他来问你:带什么动物去可以让最难变的那种动物(即该动物变为哈利·波特自己带去的动物所需要的魔咒最长)需要的魔咒最短?例如:如果只有猫、鼠、鱼,则显然哈利·波特应该带鼠去,因为鼠变成另外两种动物都只需要念4个字符;而如果带猫去,则至少需要念6个字符才能把猫变成鱼;同理,带鱼去也不是最好的选择。

输入格式:

输入说明:输入第1行给出两个正整数N (≤100)和M,其中N是考试涉及的动物总数,M是用于直接变形的魔咒条数。为简单起见,我们将动物按1~N编号。随后M行,每行给出了3个正整数,分别是两种动物的编号、以及它们之间变形需要的魔咒的长度(≤100),数字之间用空格分隔。

输出格式:

输出哈利·波特应该带去考场的动物的编号、以及最长的变形魔咒的长度,中间以空格分隔。如果只带1只动物是不可能完成所有变形要求的,则输出0。如果有若干只动物都可以备选,则输出编号最小的那只。

输入样例:

6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80

输出样例:

4 70

Dijkstra 算法:

从 1到Nv 开始枚举,每次进行 Dijkstra 算法,计算从枚举点到所有点的最短路径长度,每次计算最长顶点到枚举点的最长距离,与之前计算的最短距离 dis 进行比较,如果更短,更新 dis 和 index 的距离,因为是从小到大开始枚举的,所以当有若干只动物的最长距离相同时,得到的肯定是编号最小的动物,这正是题目所要求的。

/**
    从 1到Nv 开始枚举,每次进行 Dijkstra 算法,计算从枚举点到所有点的最短路径长度,
    每次计算最长顶点到枚举点的最长距离,与之前计算的最短距离 dis 进行比较,如果更短,更新
    dis 和 index 的距离,因为是从小到大开始枚举的,所以当有若干只动物的最长距离相同时,得到的
    肯定是编号最小的动物,这正是题目所要求的。
*/

/**
#include <iostream>
#include <algorithm>

using namespace std;


const int maxn= 110 ,INF=0x3fffffff;
int G[maxn][maxn];
int d[maxn];
bool hs[maxn];
int dis=INF,index=0;

int Nv,Ne;

void Read(); //读入数据
bool Dijkstra(int s); //Dijkstra 算法

int main()
{
    fill(*G,*G+maxn*maxn,INF);  //千万别忘了这步
    Read();
    for(int i=1;i<=Nv;++i)
        if(Dijkstra(i)==false)
        {
            cout << "0\n";
            return 0;
        }

    cout << index << ' ' << dis << endl;

    return 0;
}

void Read()
{
    cin >> Nv >> Ne;
    for(int i=0;i<Ne;++i)
    {
        int v1,v2,w;
        cin >> v1 >> v2 >> w;
        G[v1][v2]=G[v2][v1]=w;
    }
}

bool Dijkstra(int s)
{
    fill(d,d+maxn,INF);
    fill(hs,hs+maxn,0);
    d[s]=0;

    for(int i=1 ; i<=Nv ; ++i)
    {
        int u=-1,MIN=INF;
        for(int j=1;j<=Nv;++j)
        {
            if(hs[j]==0 && d[j]<MIN)
            {
                u=j;
                MIN=d[j];
            }
        }

        if(u==-1)  //如果以 s 为起点,不能遍历整个地图,那么此地图一定是不连通的
            return false;
        hs[u]=1;

        for(int v=1;v<=Nv;++v)
        {
            if(hs[v]==0 && G[u][v]!=INF && d[u]+G[u][v]<d[v])
                d[v]=d[u]+G[u][v];
        }
    }

    int temp = *max_element(d+1,d+Nv+1); //返回迭代器范围内的最大值
    if(temp < dis)
    {
        dis=temp;
        index=s;
    }

    return true;
}
*/

Floyd 算法:

void Folyd()
{
    for(int i=1;i<=Nv;++i)
        G[i][i]=0;  //将顶点到顶点的距离变为0

    for(int k=1;k<=Nv;++k)
        for(int i=1;i<=Nv;++i)
            for(int j=1;j<=Nv;++j)
            {
                if(G[i][k]!=INF && G[k][j]!=INF && G[i][k] + G[k][j] < G[i][j])
                    G[i][j] = G[i][k] +G[k][j];
            }
}


/**
    Floyd 算法:
*/


#include <iostream>
#include <algorithm>
#include <iomanip>

using namespace std;


const int maxn= 110 ,INF=0x3fffffff;
int G[maxn][maxn];
int d[maxn];
bool hs[maxn];
int dis=INF,index=0;

int Nv,Ne;

void Read(); //读入数据
void Folyd(); //Folyd 算法
void print(); //打印数据
int FindMax(int u); //以 u 为中心点,返回最远距离 ;
void FindMin();  //返回以i为枚举点的最远距离为所有顶点中最小的 的编号;

int main()
{
    fill(*G,*G+maxn*maxn,INF);  //千万别忘了这步
    Read();

    print();

    Folyd();

    print();

    FindMin();

    return 0;
}

void Read()
{
    cin >> Nv >> Ne;
    for(int i=0;i<Ne;++i)
    {
        int v1,v2,w;
        cin >> v1 >> v2 >> w;
        G[v1][v2]=G[v2][v1]=w;
    }
}

void Folyd()
{
    for(int i=1;i<=Nv;++i)
        G[i][i]=0;  //将顶点到顶点的距离变为0

    for(int k=1;k<=Nv;++k)
        for(int i=1;i<=Nv;++i)
            for(int j=1;j<=Nv;++j)
            {
                if(G[i][k]!=INF && G[k][j]!=INF && G[i][k] + G[k][j] < G[i][j])
                    G[i][j] = G[i][k] +G[k][j];
            }
}


void print()
{
    for(int i=1;i<=Nv;++i)
    {
        for(int j=1;j<=Nv;++j)
            cout << setw(15) << G[i][j];
        cout << endl;
    }
}

int FindMax(int u) //以 u 为中心点,返回最远距离;
{
    int index=-1 , Max_dis=-1;

    for(int v=1;v<=Nv;++v)
    {
        if(G[u][v]>Max_dis)
        {
            index=v;
            Max_dis=G[u][v];
        }
    }

    return Max_dis;
}

void FindMin()  // 返回以i为枚举点的最远距离为所有顶点中最小的 的编号;
{
    int index =-1 , Min_dis=INF;

    for(int u=1;u<=Nv;++u)
    {
        int d = FindMax(u);
        if(d<Min_dis)
        {
            index = u;
            Min_dis = d;
        }

        if(d==INF)  //只要能返回INF,说明此图必定不连通
        {
            cout << 0 << endl;
            return;
        }
    }

    cout << index << ' ' << Min_dis << endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值