[JZOJ 5794] 2018.08.10【2018提高组】模拟A组&省选 旅行 {spfa}

题目

Description

悠悠岁月,不知不觉,距那传说中的pppfish晋级泡泡帝已是过 去数十年。数十年 中,这颗泡泡树上,也是再度变得精彩,各种泡泡 天才辈出,惊艳世人,然而,似乎 不论后人如何的出彩,在他们的头 顶之上,依然是有着一道身影而立。 泡泡帝,pppfish。 现在,pppfish即将带着被自己收服的无数个泡泡怪前往下一个 空间,而在前往下 一个空间的道路上,有N个中转站,和M条空间虫洞连接中转站(双向通道,可有重 边,可有环),然而,通过虫洞 是要一定的条件的,pppfish将手下所有泡泡怪编号为 1,2 … +∞,对于每个空间虫洞,有两个值L和R,表示此虫洞只允许编号从L到 R的泡 泡怪通过,pppfish现在在1号中转站,他想带尽可能多的泡 泡怪到达N号中转站,于是 pppfish找到了机智的你,希望你告诉 他最多可以带多少个泡泡怪,同时他还想知道所 有泡泡怪的编号(若 有多组解取字典序最小的一组 )

Input

第一行两个用空格隔开的整数N,M(2<=N<=1000,0<=M<=3000) 接下来M行,每行四个用空格隔开的整数a,b,l,r 表示在a,b中转站间有一个空间虫洞允许编号l~r的泡泡怪通过。(1<=a, b<=N,1<=l<=r<=1e6

Output

第一行一个整数ans,表示最多能携带的泡泡怪数量 接下来一行ans个用空格隔开的正整数,表示泡泡怪的编号,从小到大依次输出,如 果没有泡泡怪能通过只要输出“0”就可以了


解题思路spfa

根据题目的性质,可得知答案一定是一段区间。
枚举左边界 l l l,然后用 s p f a spfa spfa求最大的右边界 r r r,每次更新 a n s ans ans的值,然后用 s t a r t start start记录区间的左边界即可。
总的来说,就是一种类似贪心的思想


代码

#include<cstdio>
#include<iostream>
#include<cstring>
#define rr register 
using namespace std; 
struct node{int y,l,r,next;}a[25001];
int len,last[10100],n,m,ans,start,ma,f[10100],head,tail,q[10100]; 
bool b[10100]; 
inline int maxx(int x,int y){if (x>y) return x; return y;}
inline int minn(int x,int y){if (x<y) return x; return y;}
inline int read()
{
	int p=0; char c=getchar(); 
	while (!isdigit(c)) c=getchar(); 
	while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar(); 
	return p; 
}
void add(int x,int y,int l,int r) 
{
	a[++len]=(node){y,l,r,last[x]}; last[x]=len; 
	a[++len]=(node){x,l,r,last[y]}; last[y]=len; 
}
void write(int x) { if (x/10) write(x/10); putchar(x%10+'0'); }
void spfa(int k)
{
	memset(f,0,sizeof(f)); 
	memset(b,0,sizeof(b)); 
	head=0,b[1]=1,f[q[tail=1]=1]=ma; 	
	for (;head<tail;)
	{
		int x=q[++head]; 
		if (f[x]-k<ans)	{ b[x]=0;continue; }
		for (rr int y=last[x];y;y=a[y].next)
		 if (a[y].l<=k) {
		 	int g=minn(f[x],a[y].r); 
		 	if (f[a[y].y]<g) 
		 	{
		 	   f[a[y].y]=g;
		 	   if (!b[a[y].y]) b[q[++tail]=a[y].y]=1; 
			}
		 }
		b[x]=0; 
	}
	if (f[n]-k+1>ans) ans=f[n]-k+1,start=k; 
	return;
}
int main()
{
	n=read(),m=read(); int xa,ya,la,ra; 
	for (rr int i=1;i<=m;i++)
	 xa=read(),ya=read(),la=read(),ra=read(),add(xa,ya,la,ra),ma=maxx(ra,ma); 
	for (rr int i=1;i<=ma;i++) spfa(i); 
	write(ans); putchar('\n'); 
	for (rr int i=0;i<ans;i++)
	 write(start+i),putchar(' ');
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值