Stockbroker Grapevine----spfa最短路径算法

传送门

Stockbroker Grapevine
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 37518 Accepted: 20867

Description

Stockbrokers are known to overreact to rumours. You have been contracted to develop a method of spreading disinformation amongst the stockbrokers to give your employer the tactical edge in the stock market. For maximum effect, you have to spread the rumours in the fastest possible way. 

Unfortunately for you, stockbrokers only trust information coming from their "Trusted sources" This means you have to take into account the structure of their contacts when starting a rumour. It takes a certain amount of time for a specific stockbroker to pass the rumour on to each of his colleagues. Your task will be to write a program that tells you which stockbroker to choose as your starting point for the rumour, as well as the time it will take for the rumour to spread throughout the stockbroker community. This duration is measured as the time needed for the last person to receive the information.

Input

Your program will input data for different sets of stockbrokers. Each set starts with a line with the number of stockbrokers. Following this is a line for each stockbroker which contains the number of people who they have contact with, who these people are, and the time taken for them to pass the message to each person. The format of each stockbroker line is as follows: The line starts with the number of contacts (n), followed by n pairs of integers, one pair for each contact. Each pair lists first a number referring to the contact (e.g. a '1' means person number one in the set), followed by the time in minutes taken to pass a message to that person. There are no special punctuation symbols or spacing rules. 

Each person is numbered 1 through to the number of stockbrokers. The time taken to pass the message on will be between 1 and 10 minutes (inclusive), and the number of contacts will range between 0 and one less than the number of stockbrokers. The number of stockbrokers will range from 1 to 100. The input is terminated by a set of stockbrokers containing 0 (zero) people. 

Output

For each set of data, your program must output a single line containing the person who results in the fastest message transmission, and how long before the last person will receive any given message after you give it to this person, measured in integer minutes. 
It is possible that your program will receive a network of connections that excludes some persons, i.e. some people may be unreachable. If your program detects such a broken network, simply output the message "disjoint". Note that the time taken to pass the message from person A to person B is not necessarily the same as the time taken to pass it from B to A, if such transmission is possible at all.

Sample Input

3
2 2 4 3 5
2 1 2 3 6
2 1 2 2 2
5
3 4 4 2 8 5 3
1 5 8
4 1 6 4 10 2 7 5 2
0
2 2 5 1 5
0

Sample Output

3 2
3 10

Source





#include<iostream>
#include<vector>
#include<queue>
#include<string.h>
using namespace std;
int linjie[105][105];//利用矩阵建立领接表
int num[105];//每个节点的邻接点的个数
int n;//表示点的数量;
int m;//表示一行中几个相关的人
int time[105][105];//表示从第i个人到与i有关联第j个人的传播时间
bool isvisit[105];//表示是否该点的存在状态
int center[105];//表示该点的进队次数
int d[105];//表示从i点到第n个点的最短传播时间
int result[105];//表示若从每个点开始到所有点并行传播的最短传播时间的最大值的集合
int ri=0;//表示result数组的下标
int cnt=0;//表示从某个点到某个点的最短距离为无穷大,即是无法到达的次数
bool spfa(int s)
{
    queue<int> t;//建立队列t
    t.push(s);//源点s进队
    isvisit[s]=true;//状态在队列中
    center[s]=1;//进队次数加一
    d[s]=0;//自己到自己传播时间为0
    while(!t.empty())//假设队列没有空
    {
        int value=t.front();//取出队头
        t.pop();//将队头出队
        isvisit[value]=false;//状态设置为不在队列中
        for(int i=0;i<num[value];i++)//遍历出队点的每个邻接点
        {
            int aimindex=linjie[value][i];//取出第一个邻接点
            if(time[value][aimindex]!=0x7f7f7f7f&&d[aimindex]>d[value]+time[value][aimindex])
            {//如果两个点的传播时间不是无穷大,并且对源点到邻接点的传播最小时间大于源点到出对点的最短传播时间+两点的直接传播时间,那么就松弛
                d[aimindex]=d[value]+time[value][aimindex];

                if(isvisit[aimindex]==false)//如果没有进队,那么僵邻接点进队
                {
                    t.push(aimindex);
                    isvisit[aimindex]=true;
                    center[aimindex]++;//如果该点的入队次数大于等于n,那么就说明有负环
                }
            }
        }
    }
    return true;
}
int findmin()//从每个点到整个图最短传播时间照最小值最为最快传播到整个点的方案
{
        int tmin=0x7f7f7f7f;
        int tminindex=0;
    for(int i=0;i<n;i++)
    {
        if(tmin>result[i])
           {
            tminindex=i;
            tmin=result[i];
           }
    }
    return tminindex;
}
int findmax()//寻找从某点到所有点传播最短距离的最小值
{
    int tmax=-1;
    for(int i=0;i<n;i++)
    {
        if(tmax<d[i])
            tmax=d[i];
    }
    return tmax;
}
int main()
{
 cin>>n;//输入每个实例的端点的个数
 while(n!=0)//当端点的个数是零的时候,那么终止程序
 {
     //初始化邻接表为无穷大,时间矩阵为无穷大,结果矩阵为无穷大,,邻接表每个点的领结点数目为0;
     memset(linjie,0x7f,sizeof(linjie));
     memset(time,0x7f,sizeof(time));
     memset(result,0x7f,sizeof(result));
     memset(num,0,sizeof(num));
     cnt=0;//不连通次数设置为0
     ri=0;//result数组的下标设置为0
     for(int i=0;i<n;i++)
     {
         cin>>m;
         for(int j=0;j<m;j++)
         {
             int tindex,ttime;//读入数据
             cin>>tindex>>ttime;
             time[i][tindex-1]=ttime;//从i到tindex-1的传播时间设置为ttime
             linjie[i][num[i]++]=tindex-1;//把i的邻接点ttindex加入邻接表,数目加一
         }
     }


for(int i=0;i<n;i++)//遍历每个点,当做源点求该点到所有点的最小距离的最大值,作为整个从该点传播到整个图的最短时间
 {
     //在每次调动spfa算法的时候,进行初始化
     //将最短距离数组设置为无穷大
     memset(d,0x7f,sizeof(d));
     //将isvisit数组全部设置为alse,即还没有进队
     memset(isvisit,false,sizeof(isvisit));
     //每个点的进队次数设置为0
     memset(center,0,sizeof(center));
     spfa(i);//执行spfa
     int rmax=findmax();//寻找从i点到所有点最短距离的最大值
     if(rmax==0x7f7f7f7f)//如果最大值是无穷大
        {
            cnt++;//那么不连通的次数+1;
            continue;
        }
        result[ri++]=rmax;//否则就记录下来;
 }
if(cnt==n)//如果每次都会出现从一个点到所有点出现不连通,说明至少存在一个点是入度出度都是零的
     cout<<"disjoint"<<endl;//此时图不连通
else
{
    int rindex=findmin();//找到所有各店到所有点最小路径最大值集合中的最小值的源点下标
    cout<<rindex+1<<" "<<result[rindex]<<endl;//输出
}


  cin>>n;
 }

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值