bzoj 1576: [Usaco2009 Jan]安全路经Travel

本文解析了USACO 2009 January赛题中的安全路径问题,介绍了使用SPFA算法寻找最短路径的方法,并通过代码示例详细展示了如何解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1576: [Usaco2009 Jan]安全路经Travel

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 1434   Solved: 507
[ Submit][ Status][ Discuss]

Description

Input

* 第一行: 两个空格分开的数, N和M

* 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i

Output

* 第1..N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间.如果这样的路经不存在,输出-1.

Sample Input

4 5
1 2 2
1 3 2
3 4 4
3 2 1
2 4 3

输入解释:

跟题中例子相同

Sample Output

3
3
6

输出解释:

跟题中例子相同

HINT

Source

刚开始我傻了

竟然还想着每个点跑两次spfa

忘记还要*n了


直接上别人的题解吧,,

我觉得他讲的挺好的

我也没什么好讲的QAQ

类似的题目可以看一下51nod 1076 2条不相交的路径

具体做法方面

我跑了8000ms

听说是spfa的原因

不加slf优化还会T

#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1e5+18,M=1e5*2+18,len=1e6;
struct node
{
	int from,to,next,c;
}e[M*2];
struct edgt
{
	int from,to,c;
}ee[M*2];
int first[N],bo[N],dis[N],qu[len+6],ans[N];
int cnt=0;
int fa[N],f[N];
void swap(int &a,int &b)
{
	int temp=b;b=a;a=temp;
}
bool cmp(edgt a,edgt b)
{
	return a.c<b.c;
}
int get(int v)
{
	return f[v]==v?v:f[v]=get(f[v]);
}
inline void insert(int u,int v,int c)
{
	e[++cnt]=(node){u,v,first[u],c};first[u]=cnt;
	e[++cnt]=(node){v,u,first[v],c};first[v]=cnt;
}
void spfa()     
{               
	memset(dis,127,sizeof(dis));
	int head=1,tail=2;
	qu[1]=1;dis[1]=0;bo[1]=1;
	while(head!=tail)
	{
		int rr=qu[head++];if(head==len)	head=0;
		bo[rr]=0;
		for(int k=first[rr];k;k=e[k].next)
		if(dis[e[k].to]>dis[rr]+e[k].c)
		{
			dis[e[k].to]=dis[rr]+e[k].c;
			fa[e[k].to]=rr;
			if(!bo[e[k].to])
			{
				bo[e[k].to]=1;
				if(dis[e[k].to]<dis[qu[head]])	
				{
					head--;if(head<0)	head=len-1;
					qu[head]=e[k].to;
				}
				else	
				{
					qu[tail++]=e[k].to;if(tail==len)	tail=0;
				}
			}
		}
	}
}
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	int u,v,c;
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d",&u,&v,&c);
		insert(u,v,c);
	}
	spfa();
	int tot=0;
	for(int i=1;i<=cnt;i++)
	{
	 	int u=e[i].from,v=e[i].to,c=e[i].c;
		if(fa[u]==v||fa[v]==u)	continue;	
		ee[++tot]=(edgt){u,v,c+dis[u]+dis[v]};
	}
	std::sort(ee+1,ee+1+tot,cmp);
	memset(ans,-1,sizeof(ans));
	for(int i=1;i<=n;i++)	f[i]=i;
	for(int i=1;i<=tot;i++)
	{
	 	int u=ee[i].from,v=ee[i].to,c=ee[i].c;
		u=get(u),v=get(v);
		while(u!=v)
		{
			if(dis[u]<dis[v])	swap(u,v);
			ans[u]=c-dis[u];
			int faa=get(fa[u]);
			f[u]=faa;
			u=faa;
		}
	}
	for(int i=2;i<=n;i++)	printf("%d\n",ans[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值