zoukankan      html  css  js  c++  java
  • codeforces 723F 并查集+贪心

    先去掉(s)(t)做一个最小生成森林并缩点,然后把缩后的点分成三类:
      - I. 不与(s)(t)中任意一个点相连。若存在这类点则无解;
      - II. 仅与(s)(t)中的一个点相连。肯定要连上。
      - III. 与(s)(t)都相连。在II型点都处理完后再处理III型点。贪心一下,每次取(s)(t)中所剩的度数较多那一个连之即可;如果到过程中发现度数不够,则无解。
      但要注意一个细节!如果(s)(t)在原图中就是相连的,必须连这条边的充要条件是:所有缩后的点都是II型点。因为我们要保证(s)(t)相连,所以有两种选择:一是把一个III型点的两条边都连上(如果有III型点);二是连(s)(t)的边(如果有)。显然,如果存在III型点,还连s-t边的方案不会更优。所以,只有当迫不得已(全都是II型点)的时候,才连s-t边救场子。反过来,如果全是II型点却没有s-t边,是无解的。
      用一堆数组记录方案。
      代码如下:

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
     #define rep(i,a,b) for (int i = a; i <= b; i++) 
     #define dep(i,a,b) for (int i = a; i >= b; i--)
     #define vep(i,v) for (int i = 0; i < (int)v.size(); i++)
     #define read(x) scanf("%d", &x)
     #define fill(a,x) memset(a, x, sizeof(a))
     #define mp make_pair
     #define pb push_back
    
     const int N = 200000 + 5, M = 400000 + 5;
    
     int n, m, u[M], v[M], s, t, ds, dt, cnt = 0, id[N], from[N][2], fa[N];
     bool con[N][2], link[N][2], need_direct = true;
     vector<pair<int, int> > ans;
    
     int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    
     void init() {
     	fill(con, false);
     	fill(link, false);
     	fill(id, 0);
     }
    
     bool is_st(int x) { return (x == s || x == t); }
    
    int main()
    {
    	read(n); read(m);
    	rep(i,1,m) read(u[i]), read(v[i]);
    	read(s); read(t); read(ds); read(dt);
    
    	init();
    	rep(i,1,m) {
    		if (u[i] == s) con[v[i]][0] = true;
    		if (u[i] == t) con[v[i]][1] = true;
    		if (v[i] == s) con[u[i]][0] = true;
    		if (v[i] == t) con[u[i]][1] = true;
    	}
    
        rep(i,1,n) fa[i] = i;
    	rep(i,1,m) {
    		int x = u[i], y = v[i];
    		if (is_st(x) || is_st(y)) continue;
    		int f1 = find(x), f2 = find(y);
    		if (f1 != f2) { fa[f1] = f2; ans.pb(mp(x, y)); }
    	}
    
    	rep(i,1,n) {
    		if (is_st(i)) continue;
    		int f = find(i);
    		if (!id[f]) { cnt++; id[f] = cnt; }
    		int j = id[f];
    		if (con[i][0]) { link[j][0] = true; from[j][0] = i; }
    		if (con[i][1]) { link[j][1] = true; from[j][1] = i; }
    	}
    
    	rep(i,1,cnt) 
    		if (link[i][0] ^ link[i][1]) {
    			if (link[i][0]) { ds--; ans.pb(mp(from[i][0], s)); }
    			if (link[i][1]) { dt--; ans.pb(mp(from[i][1], t)); }
    		}
    		else {
    			need_direct = false;
    			if ((link[i][0] | link[i][1]) == 0) { printf("No
    "); return 0; }
    		}
    
        bool st_have_linked = false;
    	if (need_direct) {
    		rep(i,1,m) 
    			if (is_st(u[i]) && is_st(v[i])) { 
    				dt--; ds--;
    				ans.pb(mp(t, s));
    				need_direct = false;
    				break;
    			}
    			if (need_direct) { printf("No
    "); return 0; }
    	}
    	else 
    		rep(i,1,cnt) if (link[i][0] & link[i][1]) {
    			if (!st_have_linked) { 
    				ds--; ans.pb(mp(from[i][0], s)); 
    				dt--; ans.pb(mp(from[i][1], t));
    				st_have_linked = true;
    				continue;
    			}
    			if (ds >= dt) 
    				{ ds--; ans.pb(mp(from[i][0], s)); }
    			else
    				{ dt--; ans.pb(mp(from[i][1], t)); }
    			if (ds < 0 || dt < 0) { printf("No
    "); return 0; }
    	}
    	
    	if (ds < 0 || dt < 0) { printf("No
    "); return 0; }
    	printf("Yes
    ");
    	vep(i,ans) printf("%d %d
    ", ans[i].first, ans[i].second);
    
    	return 0;
    }
    
    
  • 相关阅读:
    搭建一个属于私人博客
    Python正则表达式的匹配规则
    CentOS 使用yum 安装node.js
    一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在有一个字典,用户输入一个单词,从字典找出这个单词有多少个兄弟单词
    Clion报错 CMake Error at CMakeLists.txt:1 (cmake_minimum_required): CMake 3.
    给定一个整数sum,从n个有序的元素的数组中寻找a,b,使得a+b的结果最接近sum,最快的时间复杂度?
    Go语言通过Docker Go语言SDK获取docker stats的信息
    通过GO程序获取docker version的基本信息
    Go语言实现通过Docker SDK获取docker ps 命令信息&SDK 中docker ps源码解析
    Docker监控docker stats命令的使用与返回参数的意思
  • 原文地址:https://www.cnblogs.com/yearwhk/p/5932055.html
Copyright © 2011-2022 走看看