Silver Cow Party(最短路+反向建图的含义)

Silver Cow Party POJ - 3268
来自N 个农场 (1 ≤ N ≤ 1000) 中每一个的一头奶牛,编号为 1… N将参加在农场 # X (1 ≤ X ≤ N )举行的大型奶牛派对。共有M (1 ≤ M ≤ 100,000) 个单向(单向道路连接成对的农场;道路i需要T i (1 ≤ T i ≤ 100) 个单位的时间来遍历。

每头牛都必须步行去参加聚会,聚会结束后,回到她的农场。每头牛都是懒惰的,因此选择了最短时间的最佳路线。由于道路是单向的,一头牛的返回路线可能与她原先的路线不同

在所有奶牛中,一头奶牛必须花在去参加聚会和回来的最长时间是多少

输入
分别三空格隔开的整数,:1线Ñ,中号,和X
线2 …中号1:线我1描述了道路我有三个空格隔开的整数:甲我,乙我和Ť我。所描述的道路从农场A i延伸到农场B i,需要T i 个时间单位来遍历。
输出
第 1 行:一个整数:任何一头牛必须行走的最长时间。
样本输入
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
样本输出
10
暗示
奶牛 4 直接进入聚会(3 个单位)并通过农场 1 和 3(7 个单位)返回,总共 10 个时间单位。
思路:全部奶牛都要聚集在一个k点开party,同时party完后奶牛要回家,所以要2次最短路,第一次最短路,就是我们平时正常做的最短路,建好图,然后让k点为起点,开始迪杰斯特拉跑一下。然后得出的dis[x](1—x—N)含义就是从以k点为起点,到个点x的最短距离。本题重点在于奶牛出发到k点的最短距离(我们思考因为这个题是单向图),所以各个x点到k点的距离,求法:反向建图,并以k为起点,跑出来的dis[x]就是正向图中x到k点的最小距离。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
int n,m,k,cnt1,cnt2;
const int N=100100;
int head1[1200],head2[1200];
int dis1[1200],dis2[1200],vist[1200];
void into()
{
	cnt1=0;
	cnt2=0;
	memset(head1,-1,sizeof(head1));
	memset(head2,-1,sizeof(head2));
}
struct Edge{
	int to;
	int w;
	int next;
}edge1[N],edge2[N];

void add_edge(int u,int v,int w)
{
	edge1[cnt1].to=v;
	edge1[cnt1].w=w;
	edge1[cnt1].next=head1[u];
	head1[u]=cnt1++;
}
void radd_edge(int u,int v,int w)
{
	edge2[cnt2].to=v;
	edge2[cnt2].w=w;
	edge2[cnt2].next=head2[u];
	head2[u]=cnt2++;
}
struct Node{
	int id;
	int zhi;
	friend bool operator<(const Node& a,const Node& b){
		return a.zhi>b.zhi;
	}
};
void dij1()
{
	memset(vist,0,sizeof(vist));
	memset(dis1,0x3f3f3f,sizeof(dis1));
	dis1[k]=0;
	priority_queue<Node> q;
	q.push({k,0});
	while(!q.empty()){
		Node cur=q.top();
		q.pop();
		int dang=cur.id;
		if(vist[dang]) continue;
		vist[dang]=1;
		for(int i=head1[dang];~i;i=edge1[i].next){
			int next=edge1[i].to;
			if(!vist[next]&&dis1[next]>dis1[dang]+edge1[i].w){
				dis1[next]=dis1[dang]+edge1[i].w;
				q.push({next,dis1[next]});
			}
		}
	}	
}
void dij2()
{
	memset(vist,0,sizeof(vist));
	memset(dis2,0x3f3f3f,sizeof(dis2));
	dis2[k]=0;
	priority_queue<Node> q;
	q.push({k,0});
	while(!q.empty()){
		Node cur=q.top();
		q.pop();
		int dang=cur.id;
		if(vist[dang]) continue;
		vist[dang]=1;
		for(int i=head2[dang];~i;i=edge2[i].next){
			int next=edge2[i].to;
			if(!vist[next]&&dis2[next]>dis2[dang]+edge2[i].w){
				dis2[next]=dis2[dang]+edge2[i].w;
				q.push({next,dis2[next]});
			}
		}
	}	
}
int main()
{
	int i,j,u,v,w;
	while(cin>>n>>m>>k){
		into();
		for(i=1;i<=m;i++){
			scanf("%d%d%d",&u,&v,&w);
				add_edge(u,v,w);
				radd_edge(v,u,w);
			}
		
		dij1();
		dij2();
		int ans=0;
		for(i=1;i<=n;i++){
			ans=max(ans,dis1[i]+dis2[i]);
		}
		printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值