枚举+求桥 Codeforces701F Break Up
2016-07-23 19:51
197 查看
传送门:点击打开链接
题意:最多删掉2条边,使得无向图中s到t不连通。点数<=1e3,边数<=3e4
思路:我们先求一条s到t的任意路径。
我们很容易就能证明,如果存在这样的2条边,或者说只需要删一条边就能让他们两个不连通,那么必然是在s到t的一条路径上。
所以,我们首先求出任意一条s到t的路径。
然后枚举这条路径上的边,最多也只有n-1条。
枚举完后,把这条边删了,求桥,而且这个桥必须要满足,S和T分别在桥的两端。
我们可以这样来判断这种桥是否存在。
首先我们从S开始tarjan,当我们枚举u的一条边e,另一个点是v时候,发现DFN[u]<Low[v],说明这条边是桥,然后我们又发现DFN[v]<=DFN[T],T表示终点,此时就说明,T和v在桥的相同一侧,也就是说T和S就恰好分别在桥的两边了。
找到这样的桥后,再和我们之前枚举删除的边的权值加起来组合更新答案即可。
我通常对于这种方案比较复杂的,写一个Ans的结构体,之后维护方案感觉方便的多
题意:最多删掉2条边,使得无向图中s到t不连通。点数<=1e3,边数<=3e4
思路:我们先求一条s到t的任意路径。
我们很容易就能证明,如果存在这样的2条边,或者说只需要删一条边就能让他们两个不连通,那么必然是在s到t的一条路径上。
所以,我们首先求出任意一条s到t的路径。
然后枚举这条路径上的边,最多也只有n-1条。
枚举完后,把这条边删了,求桥,而且这个桥必须要满足,S和T分别在桥的两端。
我们可以这样来判断这种桥是否存在。
首先我们从S开始tarjan,当我们枚举u的一条边e,另一个点是v时候,发现DFN[u]<Low[v],说明这条边是桥,然后我们又发现DFN[v]<=DFN[T],T表示终点,此时就说明,T和v在桥的相同一侧,也就是说T和S就恰好分别在桥的两边了。
找到这样的桥后,再和我们之前枚举删除的边的权值加起来组合更新答案即可。
我通常对于这种方案比较复杂的,写一个Ans的结构体,之后维护方案感觉方便的多
#include <map> #include <set> #include <cmath> #include <ctime> #include <stack> #include <queue> #include <cstdio> #include <cctype> #include <bitset> #include <string> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #include <functional> #define fuck(x) cout<<"["<<x<<"]"; #define FIN freopen("input.txt","r",stdin); #define FOUT freopen("input.txt","w+",stdout); //#pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; typedef pair<int, int> PII; const int MX = 1e3 + 5; const int INF = 0x3f3f3f3f; struct Edge { int u, v, nxt, cost; } E[200005]; int n, m, S, T, dfn, del, ans1, ansid; int Head[MX], erear; int DFN[MX], Low[MX]; void edge_init() { erear = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int u, int v, int cost) { E[erear].u = u; E[erear].v = v; E[erear].cost = cost; E[erear].nxt = Head[u]; Head[u] = erear++; } inline int read() { char c = getchar(); while(!isdigit(c)) c = getchar(); int x = 0; while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x; } class Path { public: bool vis[MX]; int S[MX], E[MX], fa[MX], sz; void solve() { sz = 0; memset(vis, 0, sizeof(vis)); queue<int>Q; Q.push(::S); vis[::S] = 1; fa[::S] = -1; bool ok = 0; int u, v; while(!Q.empty()) { u = Q.front(); Q.pop(); if(u == T) { ok = 1; break; } for(int i = Head[u]; ~i; i =::E[i].nxt) { v =::E[i].v; if(vis[v]) continue; Q.push(v); vis[v] = 1; fa[v] = u; E[v] = (i + 2) / 2; } } if(!ok) return; u = T; while(fa[u] != -1) { S[++sz] = E[u]; u = fa[u]; } } } path; struct Ans { int id[2]; int num, totcost; Ans() { num = 0; totcost = 2 * INF; } void print() { if(totcost == 2 * INF) printf("-1\n"); else { printf("%d\n%d\n", totcost, num); for(int i = 0; i < num; i++) printf("%d ", id[i]); } } }; int P[MX]; int find(int x) { return P[x] == x ? x : (P[x] = find(P[x])); } void tarjan(int u, int e) { Low[u] = DFN[u] = ++dfn; for(int i = Head[u]; ~i; i = E[i].nxt) { if((i + 2) / 2 == del) continue; int v = E[i].v; if(!DFN[v]) { tarjan(v, i | 1); Low[u] = min(Low[u], Low[v]); if(Low[v] > DFN[u] && DFN[v] <= DFN[T] && ans1 > E[i].cost) { ansid = (i + 2) / 2; ans1 = E[i].cost; } } else if((i | 1) != e && DFN[v] < DFN[u]) { Low[u] = min(Low[u], DFN[v]); } } } void find_bridge() { ans1 = INF; dfn = 0; memset(DFN, 0, sizeof(DFN)); tarjan(S, -1); } int main() { //FIN; edge_init(); scanf("%d%d", &n, &m); scanf("%d%d", &S, &T); for(int i = 1; i <= n; i++) P[i] = i; for(int i = 1; i <= m; i++) { int u = read(), v = read(), cost = read(); edge_add(u, v, cost); edge_add(v, u, cost); int p1 = find(u), p2 = find(v); P[p1] = p2; } if(find(S) != find(T)) { printf("0\n0\n"); return 0; } Ans ans; path.solve(); find_bridge(); if(ans1 != INF) { ans.num = 1; ans.totcost = ans1; ans.id[0] = ansid; } for(int i = 1; i <= path.sz; i++) { del = path.S[i]; //uck(del); find_bridge(); //printf("[%d,%d] %d\n", del, ansid, ans); if(ans1 != INF && ans1 + E[(del - 1) * 2].cost < ans.totcost) { ans.num = 2; ans.id[0] = ansid; ans.id[1] = del; ans.totcost = ans1 + E[(del - 1) * 2].cost; } } ans.print(); return 0; }
相关文章推荐
- java-学习-自我规划
- POJ1995 Raising Modulo Numbers
- 【bzoj1007】[HNOI2008]水平可见直线
- [概率dp 矩阵乘法] poj 3744 Scout YYF I
- IPTABLES-小结
- POJ 1258 Agri-Net
- java-面试-阿里
- POJ3468(线段树成段增加)
- hdu 5730(分治FFT)
- svn1
- 结构体和方法
- 【bzoj2462】[BeiJing2011]矩阵模板
- HDU 1863 畅通工程
- cocoapods的安装和使用 总结
- LeetCode[368] Largest Divisible Subset
- CodeForces 427A Police Recruits
- 杭电ACM--HDU-2053a/b+c/d和HDU-2504又见gcd
- poj1611 简单并查集
- 【bzoj4320】ShangHai2006 Homework
- 《计算机图形学》学习笔记 0