usaco 月赛 2007 Cow Traffic 题解

Cow Traffic
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 3603   Accepted: 987

Description

The bovine population boom down on the farm has caused serious congestion on the cow trails leading to the barn. Farmer John has decided to conduct a study to find the bottlenecks in order to relieve the 'traffic jams' at milking time.

The pasture contains a network of M (1 ≤ M ≤ 50,000) one-way trails, each of which connects exactly two different intersections from the set of N (1 ≤ N ≤ 5,000) intersections conveniently numbered 1..N; the barn is at intersection number N. Each trail connects one intersection point to another intersection point with a higher number. As a result, there are no cycles and, as they say on the farm, all trails lead to the barn. A pair of intersection points might be connected by more than one trail.

During milking time rush hour, the cows start from their respective grazing locations and head to the barn. The grazing locations are exactly those intersection points with no trails connecting into them. Each cow traverses a 'path', which is defined as a sequence of trails from a grazing location to the barn.

Help FJ finding the busiest trail(s) by computing the largest number of possible paths that contain any one trail. The answer is guaranteed to fit in a signed 32-bit integer.

Input

Line 1: Two space-separated integers:  N and  M
Lines 2.. M+1: Two space-separated intersection points.

Output

Line 1: The maximum number of paths passing through any one trail.

Sample Input

7 7
1 3
3 4
3 5
4 6
2 3
5 6
6 7

Sample Output

4

Hint

Here are the four possible paths that lead to the barn: 
1 3 4 6 7 
1 3 5 6 7 
2 3 4 6 7 
2 3 5 6 7

Source

USACO 2007 March Silver

【大意】有N(N<=5000)个点,M条边(M<=50000)。(可能有重复边)起点可以是任何一个入度为0的点,终点是N。求从起点到终点的所有路中,经过次数最大的一条路。输出经过次数。

【分析】这道题的特点就是范围大。N^2的效率就已经撑死了。

【思路1】先N^2的DP求出到终点的路径条数P。然后枚举每一条边,把它删掉,再做一次,路径条数是Q。该条边的经过次数就是P-Q。效率是:O(n^2+m*n^2)显然是不行的。

【思路2】正解。注意一个细节:边是有向边而且一定是从编号小的点到编号大的点。即我们可以用(N+M)的效率求出到每一个点的方案数。然而这有什么用呢?如果把边都反一下,再到着做一边,那么对于某一条边P,它的方案数就是f1[S]*f2[T]。S和T是连接它的顶点数。

【代码】

#include<stdio.h>
#include<cstring>
using namespace std;
const int v=5000+5;
const int e=50000+5;
struct arr{int went,next;}a1[e],a2[e];
int begin1[v],begin2[v],end1[v],end2[v],f1[v],f2[v],come[v];
int n,m,i,x,y,cnt,cnt1,cnt2,j,go,ans;
void make_come(int u,int v)
{
  a1[++cnt1].went=v;
  if (begin1[u]==0) {begin1[u]=cnt1;end1[u]=cnt1;}
  else {a1[end1[u]].next=cnt1;end1[u]=cnt1;}
}
void make_back(int u,int v)
{
  a2[++cnt2].went=v;
  if (begin2[u]==0) {begin2[u]=cnt2;end2[u]=cnt2;}
  else {a2[end2[u]].next=cnt2;end2[u]=cnt2;}
}
int main()
{
  freopen("traffic.in","r",stdin);
  freopen("traffic.out","w",stdout);
  scanf("%ld%ld",&n,&m);
  for (i=1;i<=m;i++)
  {
    scanf("%ld%ld",&x,&y);
    make_come(x,y);come[y]++;
    make_back(y,x);
  }
  cnt=0;
  for (i=1;i<=n;i++)
  {
    if (come[i]==0) f1[i]=1;
    j=begin1[i];
    while (j>0)
    {
      go=a1[j].went;f1[go]+=f1[i];
      j=a1[j].next;
    }
    cnt++;
  }
  cnt=0;
  f2[n]=1;
  for (i=n;i>0;i--)
  {
    j=begin2[i];
    while (j>0)
    {
      go=a2[j].went;f2[go]+=f2[i];
      j=a2[j].next;
    }
    cnt++;
  }
  for (i=1;i<=n;i++)
  {
    j=begin1[i];
    while (j>0)
    {
      go=a1[j].went;
      if (f1[i]*f2[go]>ans) ans=f1[i]*f2[go];
      j=a1[j].next;
    }
  }
  printf("%ld",ans);
  return 0;
}    

你可能感兴趣的:(题解,poj,图,usaco月赛)