卧薪尝胆,厚积薄发。
提高A组模拟 旅行
Date: Fri Aug 10 22:41:06 CST 2018 In Category: NoCategory

Description:

一个人带着许多手下,一条边只允许编号 $[L,R]$ 的人通过,问最多能带几个人。
$1\le n \le 1000$ $1\le m \le 3000$

Solution:

题意就是找一条路径使得 $minr-maxl+1$ 最大。
先把 $l$ 离散化,枚举每个 $l$ ,用 $SPFA$ 求出每个点可能的最大的 $r$ ,用 $r-l+1$ 更新 $ans$ 即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 1010
#define MAXM 3010
struct edge
{
int to,nxt,l,r;
}e[MAXM << 1];
int edgenum = 0;
int lin[MAXN] = {0};
void add(int a,int b,int l,int r)
{
++edgenum;e[edgenum].to = b;e[edgenum].l = l;e[edgenum].r = r;e[edgenum].nxt = lin[a];lin[a] = edgenum;
++edgenum;e[edgenum].to = a;e[edgenum].l = l;e[edgenum].r = r;e[edgenum].nxt = lin[b];lin[b] = edgenum;
return;
}
int d[MAXN];
bool v[MAXN];
int s[MAXM],tot = 0;
int main()
{
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%d%d",&n,&m);
int a,b,l,r;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d%d",&a,&b,&l,&r);
add(a,b,l,r);
s[++tot] = l;
}
sort(s + 1,s + 1 + tot);
int ans = 0;
int left;
for(int t = 1;t <= m;++t)
{
memset(d,0,sizeof(d));
memset(v,false,sizeof(v));
d[1] = 0x3f3f3f3f;
queue<int> q;
q.push(1);
while(!q.empty())
{
int k = q.front();q.pop();
v[k] = false;
for(int i = lin[k];i != 0;i = e[i].nxt)
{
if(e[i].l <= s[t] && d[e[i].to] < min(d[k],e[i].r))
{
d[e[i].to] = min(d[k],e[i].r);
if(!v[e[i].to])
{
v[e[i].to] = true;
q.push(e[i].to);
}
}
}
}
if(d[n] - s[t] + 1 > ans)
{
ans = d[n] - s[t] + 1;
left = s[t];
}
}
cout << ans << endl;
for(int i = left;i <= left + ans - 1;++i)printf("%d ",i);puts("");
fclose(stdin);
fclose(stdout);
return 0;
}
In tag: 图论-SPFA
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡