列表

详情


NC19942. [CQOI2016]不同的最小割

描述

学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割。对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割。
而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了。我们可以把视野放宽,考虑有N个点的无向连通图中所有点对的最小割的容量,共能得到N(N−1) 2个数值。 这些数值中互不相同的有多少个呢?这似乎是个有趣的问题。

输入描述

输入文件第一行包含两个数N,M,表示点数和边数。
接下来M行,每行三个数u,v,w,表示点u和点v(从1开始标号)之间有条边权值是w。
1 ≤ N ≤ 850,1 ≤ M ≤ 8500,1 ≤ W ≤ 100000

输出描述

输出文件第一行为一个整数,表示个数。

示例1

输入:

4 4
1 2 3
1 3 6
2 4 5
3 4 4

输出:

3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 999ms, 内存消耗: 740K, 提交时间: 2020-07-01 18:12:08

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 855, MAXM = 20005, INF = 0x3f3f3f3f;
struct Graph { int u, v, w; } gra[MAXM];
struct Edge { int to, cap, next; } edge[MAXM];
int head[MAXN], id[MAXN], dis[MAXN], que[MAXN], p[MAXN], q[MAXN], n, m, tot;
set<int> ans;
void addedge(int u, int v, int w) {
	edge[tot] = (Edge) { v, w, head[u] };
	head[u] = tot++;
	edge[tot] = (Edge) { u, w, head[v] };
	head[v] = tot++;
}
int bfs(int s, int t) {
	int he = 0, ta = 0;
	memset(dis, -1, sizeof(dis));
	dis[que[ta++] = s] = 0;
	while (he < ta) {
		int u = que[he++];
		for (int i = head[u]; ~i; i = edge[i].next) {
			int v = edge[i].to;
			if (edge[i].cap > 0 && dis[v] < 0)
				dis[que[ta++] = v] = dis[u] + 1;
		}
	}
	return dis[t] >= 0;
}
int dfs(int u, int t, int f) {
	if (u == t) return f;
	int flow = 0;
	for (int i = id[u]; ~i; i = edge[i].next) {
		int v = edge[i].to;
		if (dis[v] == dis[u] + 1 && edge[i].cap > 0) {
			int d = dfs(v, t, min(f, edge[i].cap));
			if (!d) continue;
			edge[i].cap -= d, edge[i ^ 1].cap += d;
			f -= d, flow += d;
			if (!f) {
				id[u] = i;
				return flow;
			}
		}
	}
	id[u] = -1;
	return flow;
}
int dinic(int s, int t) {
	int flow = 0;
	while (bfs(s, t)) {
		memcpy(id, head, sizeof(id));
		flow += dfs(s, t, INF);
	}
	return flow;
}
void rebuild() {
	memset(head, -1, sizeof(head));
	tot = 0;
	for (int i = 1; i <= m; i++)
		addedge(gra[i].u, gra[i].v, gra[i].w);
}
void solve(int l, int r) {
	if (l == r) return;
	rebuild();
	int s = p[l], t = p[r], tl = l, tr = r, cur = dinic(s, t);
	ans.insert(cur);
	for (int i = l; i <= r; i++)
		if (dis[p[i]] >= 0) q[tl++] = p[i];
		else q[tr--] = p[i];
	for (int i = l; i <= r; i++) p[i] = q[i];
	solve(l, tl - 1), solve(tl, r); 
} 
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
		scanf("%d%d%d", &gra[i].u, &gra[i].v, &gra[i].w);
	for (int i = 1; i <= n; i++) p[i] = i;
	solve(1, n);
	printf("%d\n", ans.size());
	return 0;
}

上一题