您的位置:首页 > 其它

HDU 5452 Minimum Cut(LCA+树形DP)

2015-09-21 01:26 316 查看
题意:给一个简单无向图,并给图上的一个最小生成树,问最少去除多少边使得该图不连通,去掉的边中有且仅能有一条是生成树上的边。

思路:首先考虑枚举树上的每条边,假设一条树边所连的两个节点为u,v(u为深度较小的点,v为深度较大的点),

那么这条树边所在的最小割边集等于以v为根节点的子树向子树外的点连的边的数量加1,

于是我们可以考虑用树形DP来做,以结点R为根节点的子树向外连的边数等于它所有子树向外连的边数之和减去以R为LCA的结点对数乘2,这是因为可能有一些子树之间互连了,而且每条边算了两遍所以乘2。

PS:这道题因为数据很弱只有五组case,所以比赛时很多人水过去了....

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 20000 + 1000;
const int INF = 0x3f3f3f3f;
int n, m, ans;
vector<int> T[MAXN], G[MAXN];
int num[MAXN], pnt[MAXN];
bool vis[MAXN];
void init() {
	for(int i = 1; i <= n; i++) T[i].clear(), G[i].clear();
	memset(num, 0, sizeof(num));
	memset(vis, 0, sizeof(vis));
	ans = INF;
}
int Find(int x) {
	if(x == pnt[x]) return x;
	return pnt[x] = Find(pnt[x]);
}
void dfs(int cur, int fa) {
	vis[cur] = 1; pnt[cur] = cur;
	int sz = T[cur].size();
	for(int i = 0; i < sz; i++) {
		int u = T[cur][i];
		if(u == fa) continue;
		dfs(u, cur);
		num[cur] += num[u];
		pnt[u] = cur;
	}
	sz = G[cur].size();
	for(int i = 0; i < sz; i++) {
		int u = G[cur][i];
		if(vis[u]) num[Find(u)] -= 2;
		num[cur]++;
	}
}
int main() {
    //freopen("input.txt", "r", stdin);
	int t; cin >> t;
	int kase = 0;
	while(t--) {
		scanf("%d%d", &n, &m);
		init();
		for(int i = 1; i < n; i++) {
			int u, v;
			scanf("%d%d", &u, &v);
			T[u].push_back(v);
			T[v].push_back(u);
		}
		for(int i = n; i <= m; i++) {
			int u, v;
			scanf("%d%d", &u, &v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		dfs(1, 0);
		for(int i = 2; i <= n; i++) ans = min(ans, num[i]+1);
		printf("Case #%d: %d\n", ++kase, ans);
	}
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: