• LUOGU 1525 关押罪犯


    传送门

    分析:

    并查集:
    第一步先将所有矛盾从大至小排序,显然先将矛盾值大的分成两部分会更优。
    普通的并查集都只能快速合并两个元素至同一集合,却不能将两个元素分至不同集合。
    对于将很多数分成两个集合,并给出两数存在的矛盾关系(A和B不能在一集合),普通并查集无法解决。
    考虑见每个元素拆成两个点,拆出来的点是它的对立点(i+n),如果要把A和B分至不同集合,就连边 A->B+n,B->A+n(假设先不压缩路径),也就是说:将A与B的对立点分至一个集合 (Leftrightarrow) 将A与B分至不同集合。当然这种思路只能解决分成两部分的情况。

    二分+二分图染色
    其实就是要求把有矛盾的分到不同组里,于是可以使用二分图染色。先排序,然后二分不能满足的第一个位置,将前面的矛盾关系进行二分图染色,如果然不成功(相邻节点颜色相同),那么更新答案。注意二分图染色要对每个未染色的点都染一次,因为建出来的图可能不联通。

    code

    并查集:

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e4 + 50, M = 1e5 + 50;
    int n, m, anc[N * 2];
    struct node{
    	int x, y, w;
    	inline bool operator < (const node &b) const{
    		return w > b.w;
    	}
    }edge[M];
    inline int getAnc(int x){return x == anc[x] ? x : (anc[x] = getAnc(anc[x]));}
    int main(){
    	freopen("h.in", "r", stdin);
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= 2 * n; i++) anc[i] = i;
    	for(int i = 1; i <= m; i++)scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].w);
    	sort(edge + 1, edge + m + 1);
    	for(int i = 1; i <= m; i++){
    		int fx = getAnc(edge[i].x), fy = getAnc(edge[i].y);
    		if(fx == fy){
    			printf("%d
    ", edge[i].w);
    			return 0;
    		}
    		else{
    			anc[fx] = getAnc(edge[i].y + n);
    			anc[fy] = getAnc(edge[i].x + n);
    		}
    	}
    	printf("0");
    	return 0;
    }
    

    二分+二分图染色:

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2e4 + 40, M = 1e5 + 50;
    int n, m, col[N];
    vector<int> G[N];
    struct State {
    	int u, c, f;
    	State() {}
    	State(int _u, int _c, int _f):u(_u), c(_c), f(_f) {}
    };
    queue<State> que;
    struct node {
    	int a, b, c;
    	inline bool operator < (const node &g) const {
    		return c > g.c;
    	}
    } item[M];
    
    inline bool BiCheck(int mid) {
    	memset(col, -1, sizeof(int) * (n + 5));
    	while(!que.empty()) que.pop();
    	for(int i = 1; i <= n; i++) G[i].clear();
    	for(int i = 1; i <= mid; i++) {
    		G[item[i].a].push_back(item[i].b);
    		G[item[i].b].push_back(item[i].a);
    	}
    	
    	for(int i = 1; i <= n; i++){
    		if(col[i] == -1){
    			col[i] = 0;
    			que.push(State(i, 0, 0));
    			while(!que.empty()) {
    				State t = que.front();
    				que.pop();
    				int u = t.u, c = t.c, f = t.f;
    				for(int e = G[u].size() - 1; e >= 0; e--) {
    					int v = G[u][e];
    					if(v == f) continue;
    					if(col[v] != -1) {
    						if(col[v] == c) return false;
    						else continue;
    					} else col[v] = c ^ 1, que.push(State(v, c ^ 1, u));
    				}
    			}	
    		}
    		
    	}
    	return true;
    }
    
    int main() {
    	freopen("h.in", "r", stdin);
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++) scanf("%d%d%d", &item[i].a, &item[i].b, &item[i].c);
    	sort(item + 1, item + m + 1);
    
    	int l = 1, r = m, ans = 0;
    	while(l <= r) {
    		int mid = l + r >> 1;
    		if(!BiCheck(mid)) ans = item[mid].c, r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d", ans);
    	return 0;
    }
    
  • 相关阅读:
    java List 学习
    java Map 的学习
    samba服务
    linux常用命令
    解决粘包问题
    Python网络编程
    python异常处理
    python中封装
    python中继承和多态
    python面向对象基础
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7788608.html
Copyright © 2020-2023  润新知