USACO 2007 February Contest, Silver Problem 3. Silver Cow Party SPFA

题目:

问题描述:

John Farmer的牧场有n(1n1,000)头奶牛,分别住在对应编号1..n的牧场。将参加编号X(1Xn) 的奶牛牧场聚会。总共m(1m100,000)条单向道路连接成对的牧场;第i条道路需要Ti(1Ti100)单位时间。

每头奶牛都必须走到聚会,聚会结束后再返回到自己的牧场。每头奶牛都要选择一条最短路线。因为是单向道路,奶牛的回程路线可能与来时不同,所有奶牛都选择最短路线往返,请找出奶牛中花费最长的时间?

入格式:

第1行: 三个整数n(1n1,000) 头奶牛,m(1m50,000)条单向道路,将参加编号X(1Xn)奶牛牧场的聚会。

第2…m+1行: 第i+1行三个整数描述第i条单向道路,Ai,Bi表示一条道路从Ai到Bi,需要Ti(1Ti100)单位时间。

输出格式:

仅1行1个整数,表示奶牛中花费最长的时间。

输入输出样例:

sparty.in

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

sparty.out

10

输入输出解释:

总共有4头牛;8条单向道路,在编号2的牧场聚会。奶牛1往返4+1=5;奶牛2往返0;奶牛3往返2+4+1+2=9;奶牛4往返3+1+2+4=10时间最长,输出10。

程序:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int n,m,p,i,j,t[50005],k[50005],s[50005],Head[1005],f1[1005],f[1005];
 6 bool flag[1005];
 7 struct edge
 8 {
 9     int Next,Weight,Aim;
10 }Edge[50005];
11 
12 void add(int u,int v,int w,int x)
13 {
14     Edge[x].Next=Head[u];
15     Head[u]=x;
16     Edge[x].Weight=w;
17     Edge[x].Aim=v;
18 }
19 
20 void SPFA()
21 {
22     int i;
23     queue<int> Q;
24     memset(flag,0,sizeof(flag));
25     memset(f,0x3f3f3f3f,sizeof(f));
26     flag[p]=1;f[p]=0;
27     Q.push(p);
28     while (!Q.empty())
29     {
30         int t=Q.front();
31         Q.pop();
32         flag[t]=0;
33         for (i=Head[t];i;i=Edge[i].Next)
34             if (f[Edge[i].Aim]>Edge[i].Weight+f[t])
35             {
36                 f[Edge[i].Aim]=Edge[i].Weight+f[t];
37                 if (flag[Edge[i].Aim]==0)
38                 {
39                     Q.push(Edge[i].Aim);
40                     flag[Edge[i].Aim]=1;
41                 }
42             }
43     }
44 }
45 
46 int main()
47 {
48     freopen("sparty.in","r",stdin);
49     freopen("sparty.out","w",stdout);
50     cin>>n>>m>>p;
51     for (i=1;i<=m;i++)
52         cin>>t[i]>>k[i]>>s[i];
53     for (i=1;i<=m;i++)
54         add(t[i],k[i],s[i],i);
55     SPFA();
56     for (i=1;i<=n;i++)
57         f1[i]=f[i];
58     memset(Head,0,sizeof(Head));
59     for (i=1;i<=m;i++)
60         add(k[i],t[i],s[i],i);
61     SPFA();
62     int ans=0;
63     for (i=1;i<=n;i++)
64         ans=max(ans,f[i]+f1[i]);
65     cout<<ans<<endl;
66     return 0;
67 }

 

分析:

这道题目显然就是一个单源最短路。先按照原图从聚会的地方往牧场的方向跑SPFA,然后反过来从牧场的方向往聚会的地方跑SPFA。

简单分析一下SPFA的原理。

简单来说SPFA的形式和广度优先搜索(BFS)有些类似。首先建立一个队列Q,队列中存储的是所有待处理的点。在队列非空时开始循环,弹出队首元素存入t,然后循环所有以为开始节点的边。如果当前循环的边的终点的最短路长度可以更新,那么就更新它(废话)。这个点的值被更新过以后,意味着这条边的终点也成为了一个需要处理的点。如果它现在不在队列中,把它加入队列,作为一个需要处理的点。SPFA:

 procedure Shortest-Path-Faster-Algorithm(G, s)
  1    for each vertex v ≠ s in V(G)
  2        d(v) := ∞
  3    d(s) := 0
  4    offer s into Q
  5    while Q is not empty
  6        u := poll Q
  7        for each edge (u, v) in E(G)
  8            if d(u) + w(u, v) < d(v) then
  9                d(v) := d(u) + w(u, v)
 10                if v is not in Q then
 11                    offer v into Q

 

posted @ 2017-12-23 22:51  OptimusPrime_L  阅读(239)  评论(0编辑  收藏  举报