码迷,mamicode.com
首页 > 其他好文 > 详细

codeforces 141C Clearing Up

时间:2016-10-22 17:51:00      阅读:251      评论:0      收藏:0      [点我收藏+]

标签:代码   tin   amp   names   ace   turn   code   continue   algo   

题意:

给出n个点,m条边,边有两种,求一棵生成树,使得这棵树中的两种边数量相等。

 

题解:

不妨令第一种边的边权为-1,第二种边权为1,首先求一个最小生成树,尽量使用-1的边,然后对所有使用的边进行标记,然后初始化并查集,然后将所有用过的边权为1的边加入并查集,然后加入边权为1的边,使得生成树的边权为(n - 1) / 2,然后加入使用过的边权为-1的边使得生成树的边权为0即可。

 

代码:

 

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 1e5 + 7;
struct edge {int u, v, w, id;} e[N];

bool cmp (edge a, edge b) {return a.w < b.w;}

char ch[2];
int n, m, used[N], vis[N], pa[N];

int find (int x) {
	return x == pa[x] ? x : pa[x] = find (pa[x]);
}

int main () {
	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d%s", &e[i].u, &e[i].v, ch);
		if (ch[0] == ‘S‘) e[i].w = -1;
		else e[i].w = 1;
		e[i].id = i;
	}
	if (n % 2 == 0) {puts("-1"); return 0;}
	sort (e + 1, e + 1 + m, cmp);
	for (int i = 1; i <= n; ++i) pa[i] = i;
	int tot = 0, val = 0;
	for (int i = 1; i <= m; ++i) {
		int pu = find (e[i].u), pv = find (e[i].v);
		if (pu != pv) {
			pa[pu] = pv;
			++tot;
			val += e[i].w;
			used[e[i].id] = 1;
			if (tot == n - 1) break;
		}
	}
	if (tot < n - 1) {puts("-1"); return 0;}
	if (val > 0) {puts("-1"); return 0;}
	if (val == 0) {
		printf ("%d\n", n - 1);
		for (int i = 1; i <= m; ++i) if(used[i]) printf ("%d ", i);
		return 0;
	}
	val = 0;
	for (int i = 1; i <= n; ++i) pa[i] = i;
	for (int i = 1; i <= m; ++i) 
		if (e[i].w == 1 && used[e[i].id]) vis[e[i].id] = 1, val++, pa[find(e[i].u)] = find(e[i].v);
	for (int i = m; i >= 1; --i) {
		if (val == (n - 1) / 2) break;
		if (used[e[i].id] || e[i].w == -1) continue;
		int pu = find (e[i].u), pv = find (e[i].v);
		if (pu != pv) {val++, pa[pu] = pv, vis[e[i].id] = 1;}
	}
	if (val < (n - 1) / 2) {puts("-1"); return 0;}
	for (int i = 1; i <= m; ++i) {
		if (val == 0) break;
		if (!used[e[i].id] || e[i].w == 1) continue;
		int pu = find (e[i].u), pv = find (e[i].v);
		if (pu != pv) {val--, pa[pu] = pv, vis[e[i].id] = 1;}
	}
	if (val > 0) {puts("-1"); return 0;}
	printf ("%d\n", n - 1);
	for (int i = 1; i <= m; ++i) if (vis[i]) printf ("%d ", i);
	return 0; 
}

 

  

总结:

不知道怎么总结了。。。反正有两种不同的情况组合在一起,就设不同的权,数量相等那么正负相消,生成树嘛,就往那边想就是了QAQ

 

codeforces 141C Clearing Up

标签:代码   tin   amp   names   ace   turn   code   continue   algo   

原文地址:http://www.cnblogs.com/xgtao/p/5987873.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!