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;
}
随着牛的数量增加,农场的道路的拥挤现象十分严重,特别是在每天晚上的挤奶时间。为了解决这个问题,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++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C++的template模板中class与typename关键字的区别分析
- C与C++之间相互调用实例方法讲解