CF700C Break Up

时间:2021-09-06
本文章向大家介绍CF700C Break Up,主要包括CF700C Break Up使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

statement

给你一个 \(n\) 个点 \(m\) 条边的无向图,边有权值,要求你删去最多两条边,使得 \(s\)\(t\) 不连通,且删去的边权值和最小。

Hints

\(2\le n\le 1000\)\(0\le m \le 30000\)

solution

首先考虑删除一条边的情况,必定是有一条从 \(s\)\(t\) 的所有路径中,都经过的一条边,随便找一条路径枚举即可,时间复杂度 \(\mathcal O (n\times m)\)

两条路径的情况就是把一条边删去后,又出现了一条如上述的边,而直接枚举两条边的复杂度是 \(\mathcal O (m ^ 3)\) 的,通过 tarjan 算法判桥可以做到 \(\mathcal O (m ^ 2)\)

很容易发现,这样枚举是有完全不可能合法的方案的,运用人类智慧,发现在同一条 \(s\rightarrow t\) 的路径上必定有一条边是会被删去的。

所以直接先拉出任意一条路径,直接暴力枚举即可,时间复杂度 \(\mathcal O (n\times m)\)

struct Lst {
	int dir, nxt, w;
	Lst() {}
	Lst(int _d, int _n, int _w) : dir(_d), nxt(_n), w(_w) {}
} E[M << 1];
int G[N], cnt = 1;
inline void Add(int u, int v, int w) {E[++cnt] = Lst(v, G[u], w), G[u] = cnt;}
int n, m, s, t, ban, dfn[N], ord, brg[M], vis[M], vt[M], lst[N], res = 2e9 + 1;
vector<int> pth;
void path(int u) {
	vis[u] = 1; if(u == t) return ;
	for(register int i=G[u], v; i; i=E[i].nxt) if(i != ban && i != (ban ^ 1)) {
		v = E[i].dir; 
		if(vis[v]) continue ;
		lst[v] = i, path(v);
	}
}
int tarjan(int u) {
	int low = dfn[u] = ++ord, lowv;
	for(register int i=G[u], v; i; i=E[i].nxt) if(!vt[i]) {
		v = E[i].dir, vt[i] = vt[i ^ 1] = 1;
		if(!dfn[v]) {
			low = min(low, lowv = tarjan(v));
			if(lowv > dfn[u]) {
				brg[i >> 1] = 1;
			}
		} else if(dfn[v] < dfn[u]) low = min(low, dfn[v]);
	}
	return low;
}
int ansl, ansr;
int main() {
	scanf("%d%d%d%d", &n, &m, &s, &t);
	forn(i,1,m) {
		static int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		Add(u, v, w), Add(v, u, w);
	}
	ban = 1e9, path(s);
	if(!vis[t]) return printf("0\n0\n") & 0;
	int tmp = t;
	while(tmp != s) pth.push_back(lst[tmp]), tmp = E[lst[tmp] ^ 1].dir; 
	ansl = ansr = -1;
	rep(i,0,pth.size()) {
		ban = pth[i], ord = 0;
		memset(dfn, 0, sizeof dfn);
		memset(brg, 0, sizeof brg);
		memset(vis, 0, sizeof vis);
		memset(lst, 0, sizeof lst);
		memset(vt, 0, sizeof vt);
		vt[pth[i]] = vt[pth[i] ^ 1] = 1;
		path(s);
		if(!vis[t]) {
			if(res > E[pth[i]].w) res = E[pth[i]].w, ansl = pth[i], ansr = -1;
		} else {
			tarjan(s), tmp = t;
			while(tmp != s) {
				int e = lst[tmp];
				if(brg[e >> 1]) if(res > E[pth[i]].w + E[e].w)
					res = E[pth[i]].w + E[e].w, ansl = pth[i], ansr = e;
				tmp = E[e ^ 1].dir;
			} 
		}
	}
	if(res == 2e9 + 1) return puts("-1") & 0;
	if(ansr == -1) {
		printf("%d\n1\n", res);
		printf("%d\n", ansl >> 1);
	} else {
		printf("%d\n2\n", res);
		printf("%d %d\n", ansl >> 1, ansr >> 1);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Ax-Dea/p/15234148.html