输入n,为共有n个人
然后n行,
每行第一个数是这个人能够联系其他人的数目, 然后 剩下的数两个一组,每组第一个数表示能联系到人的编号,第二个数代表需要的时间,一次只能联系一个人。
如果从只一个人开始,能联系到所有人,求出那么时间最少的开始人编号,及所需时间。
不能联系到 输出disjoint。
http://poj.org/problem?id=1125
一道用了floyd的题
Floyd:
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单
缺点:
时间复杂度比较高,不适合计算大量数据。
时间复杂度:O(n^3);
空间复杂度:O(n^2);
[1]
从图的带权
邻接矩阵A=[a(i,j)] n×n开始,
递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出
矩阵D(n)。
矩阵D(n)的i行j列元素便是i号顶点到j号顶点的
最短路径长度,称D(n)为图的
距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用的是(松弛技术),对在i和j之间的所有其他点进行一次松弛。所以
时间复杂度为O(n^3);
其
状态转移方程如下: map[i,j]:=min{map[i,k]+map[k,j],map[i,j]}
map[i,j]表示i到j的最短距离,K是穷举
i,j的断点,map[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有map[i,k]这条路
上代码
#include <cstdio>
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn= 102;
int n;
int time[maxn][maxn]; //从前到后的时间
int cnt_num; //i能够联系到的人数
void Floyd()//若两点阻断,则时间为无穷
{
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(time[i][j]>time[i][k]+time[k][j])
time[i][j]=time[i][k]+time[k][j];
}
int solve(int x)
{
int max=-1;
for(int y=1;y<=n;y++)
if(max<time[x][y])
max=time[x][y];
return max;
}
int main()
{
//ifstream cin ("input.txt");
while(cin>>n,n)
{
//----------------------------------------------华丽的分割线
memset(time,INF,sizeof(time));
for(int i=1;i<=n;i++)
time[i][i]=0;
//----------------------------------------------华丽的分割线
for(int i=1; i<=n; i++) //第i个人
{
cin>>cnt_num;
while(cnt_num--)
{
int x;
cin>>x;
cin>>time[i][x]; //the time from 'i' to 'x'
}
}
//输入结束----------------------------------------华丽的分割线
Floyd();
int min_t=INF;
int ans;
int ok=0;
for (int i = 1; i <= n; ++i)
{
int t= solve(i);//从i出发用的最大时间 若无返回-1
if(min_t>t) min_t=t,ans=i,ok=1;
}
if(ok) cout<<ans<<" "<<min_t<<endl;
else cout<<"disjoint"<<endl;
}
return 0;
}