您的位置:首页 > 编程语言 > C语言/C++

POJ3272 奶牛交通 解题报告

2016-07-12 08:18 375 查看
【问题描述】  

  

  随着牛的数量增加,农场的道路的拥挤现象十分严重,特别是在每天晚上的挤奶时间。为了解决这个问题,FJ决定研究这个问题,以能找到导致拥堵现象的瓶颈所在。

  牧场共有M条单向道路,每条道路连接着两个不同的交叉路口,为了方便研究,FJ将这些交叉路口编号为1..N,而牛圈位于交叉路口N。任意一条单向道路的方向一定是是从编号低的路口到编号高的路口,因此农场中不会有环型路径。同时,可能存在某两个交叉路口不止一条单向道路径连接的情况。 

  在挤奶时间到来的时候,奶牛们开始从各自的放牧地点回到牛圈。放牧地点是指那些没有道路连接进来的路口(入度为0的顶点)。 

  现在请你帮助fj通过计算从放牧点到达牛圈的路径数目来找到最繁忙的道路(答案保证是不超过32位整数)。 

 

    

 【输入格式】  

  

  第一行:两个用空格隔开的整数N和M。

  接下来M行:每行两个用空格隔开的整数a,b,表示一条道路从a到b。

 

    

 【输出格式】  

   

  一个整数,表示所有路径中通过某条道路的最大次数。

 

    

 【输入样例】   

   

7 7

1 3

3 4

3 5

4 6

2 3

5 6

6 7

 

    

 【输出样例】  

   

4

 

    

 【样例解释】  

   

  奶牛通向宿舍的所有路径:(1->3->4->6->7)、(1->3->5->6->7)、(2->3->4->6->7)、(2->3->5->6->7)。其中 6->7 同过的次数为 4,是最大的。 

      

 

    

 【数据范围】  

   

1 <= M <= 50,000  1 <= N <= 5,000

 

    

 【来源】  

  

POJ3272
 

解题思路:根据题意,农场中的单向道路一定是由编号低的路口到编号高的路口,所以将路口看作点,道路看作边,所得的图是DAG图。要求最繁忙的道路可以依次判断每条道路所经过的奶牛次数,而要判断一条道路所经过的奶牛次数,可以先算出道路连接的两点,从放牧地点到起始点经过的奶牛次数和从道路末点到牛圈经过的奶牛次数,相乘即为该道路经过的奶牛次数。所以,该题的主要算法为DAG图上的动态规划(记忆化搜索)。需要注意的是,要求一个点到牛圈经过的奶牛次数,需在输入时建立反向图进行动态规划。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=5005;
int N,M,a,b;
vector<int>g[maxn],gr[maxn];
int rd[maxn];
long long d1[maxn],d2[maxn],ans=0;
long long f1(int i) //求一个点到牛圈经过的奶牛次数
{
if(i==N)
{
d1[i]=1;
return d1[i];
}
if(d1[i]) return d1[i]; //记忆化搜索,节省时间
for(int k=0;k<g[i].size();k++)
{
int j=g[i][k];
d1[i]+=f1(j);
}
return d1[i];
}
long long f2(int i) //求放牧地点到一个点经过的奶牛次数
{
if(rd[i]==0)
{
d2[i]=1;
return d2[i];
}
if(d2[i]) return d2[i]; //同样记忆化搜索
for(int k=0;k<gr[i].size();k++)
{
int j=gr[i][k];
d2[i]+=f2(j);
}
return d2[i];
}
int main()
{
freopen("48.in","r",stdin);
//freopen("48.txt","w",stdout);
scanf("%d%d",&N,&M);
memset(rd,0,sizeof(rd));
for(int i=1;i<=M;i++)
{
scanf("%d%d",&a,&b);
g[a].push_back(b);
rd[b]++; //方便查找放牧地点(入度为0的点)
gr[b].push_back(a); //需建立反向图
}
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
for(int i=1;i<=N;i++)
{
if(d1[i]==0) d1[i]=f1(i);
if(d2[i]==0) d2[i]=f2(i);
}
for(int i=1;i<=N;i++)
{
for(int k=0;k<g[i].size();k++)
{
int j=g[i][k];
ans=max(ans,d2[i]*d1[j]);
}
}
cout<<ans<<'\n';
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ POJ