题目解析
数据范围不算大,看了看题首先可以得出一个推论:答案区间一定是连续的。
所以我们只要知道区间的左右段就可以了,枚举一下就很好做了。
用并查集 + 贪心的思想,将所有边按右端点的限制大小排序,之后贪心的合并点,同时选取边,当点1和点n在同一集合内,就结束枚举,过程中记录答案。
其实有点像Kruskal的过程。
Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; //1<=a , b<=N , 1<=l<=r<=1e6 const int MAXN = 1005; const int MAXM = 3005; int n,m; int ans,cnt,lft; int fa[MAXN]; struct Edge { int from,to; int L,R; } l[MAXM << 1]; bool cmp(Edge x,Edge y) { return x.R > y.R; } int _find(int x) { if(x == fa[x]) return x; return fa[x] = _find(fa[x]); } int _min(int x,int y) { return x < y ? x : y; } int _max(int x,int y) { return x > y ? x : y; } inline void add(int x,int y,int a,int b) { cnt++; l[cnt].from = x; l[cnt].to = y; l[cnt].L = a; l[cnt].R = b; return; } inline void init_fa() { for(int i = 1;i <= n;i++) fa[i] = i; return; } inline void Dinic(int s,int t) { for(int i = 1;i <= m;i++) { init_fa(); for(int j = 1;j <= m;j++) { if(l[j].L > l[i].L) continue; fa[_find(l[j].from)] = _find(l[j].to); if (_find(1)==_find(n)) { if(l[j].R - l[i].L > ans - 1) { lft = l[i].L; ans = l[j].R - l[i].L + 1; } break; } } } return; } int main() { scanf("%d%d",&n,&m); int x,y,a,b; for(int i = 1;i <= m;i++) { scanf("%d%d%d%d",&x,&y,&a,&b); add(x,y,a,b); } for(int i = 1;i <= n;i++ ){ fa[x] = x; } sort(l+1,l+1+m,cmp); Dinic(1,n); printf("%d ",ans); for(int i = lft;i<=lft + ans - 1;i++) { printf("%d ",i); } return 0; }