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; //将顶点到顶点的距离变为0for(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;
}