zoukankan      html  css  js  c++  java
  • codeforces 141C Clearing Up

    题意:

    给出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 - 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 - 1);
    	for (int i = 1; i <= m; ++i) if (vis[i]) printf ("%d ", i);
    	return 0; 
    }
    

      

    总结:

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

  • 相关阅读:
    面试题15:链表中倒数第K个结点
    面试题31:连续子数组的最大和
    数据库索引实例
    面试题27:二叉搜索树与双向链表
    面试题28:字符串的排列
    java比较器Comparable接口和Comaprator接口
    面向对象知识汇总
    虚函数与纯虚函数
    Linux IO实时监控iostat命令详解
    hive GroupBy操作(翻译自Hive wiki)
  • 原文地址:https://www.cnblogs.com/xgtao/p/5987873.html
Copyright © 2011-2022 走看看