您的位置:首页 > 其它

枚举+求桥 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的结构体,之后维护方案感觉方便的多

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: