• Luogu P3731 [HAOI2017]新型城市化


    题目显然可以转化为求每一条边对二分图最大独立集的贡献,二分图最大独立集(=)点数(-)最大匹配数,我们就有了(50pts)做法。

    正解的做法是在原图上跑(Tarjan),最开始我想复杂了,后来才意识到,只要存在这样一个强连通分量,那么断掉分量内的任意一条边都不会破坏其连通性,即不管删掉哪个连边都一定会有新的匹配补充。只要让两个点不在同一个分量里面,而且原来是满流的(匹配可行边),那么它就是一个可用边(匹配必须边)。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 400010;
    const int M = 800010;
    const int INF = 0x3f3f3f3f;
    
    struct Graph {
    	int cnt, head[N];
    	
    	struct edge {int nxt, to, f;}e[M];
    	
    	Graph () {
    		cnt = -1;
    		memset (head, -1, sizeof (head));
    	}
    	
    	void add_edge (int u, int v, int f) {
    		e[++cnt] = (edge) {head[u], v, f}; head[u] = cnt;
    	}
    	
    	void add_len (int u, int v, int f) {
    		add_edge (u, v, f);
    		add_edge (v, u, 0);
    	}
    	
    	queue <int> q;
    	int cur[N], deep[N];
    	
    	bool bfs (int s, int t) {
    		memcpy (cur, head, sizeof (head));
    		memset (deep, 0x3f, sizeof (deep));
    		deep[s] = 0; q.push (s);
    		while (!q.empty ()) {
    			int u = q.front (); q.pop ();
    			for (int i = head[u]; ~i; i = e[i].nxt) {
    				int v = e[i].to;
    				if (deep[v] == INF && e[i].f) {
    					deep[v] = deep[u] + 1;
    					q.push (v);
    				}
    			}
    		}
    		return deep[t] != INF;
    	}
    	
    	int dfs (int u, int t, int lim) {
    		if (u == t || !lim) {
    			return lim;
    		}
    		int tmp = 0, flow = 0;
    		for (int &i = cur[u]; ~i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (deep[v] == deep[u] + 1) {
    				tmp = dfs (v, t, min (lim, e[i].f));
    				lim -= tmp;
    				flow += tmp;
    				e[i ^ 0].f -= tmp;
    				e[i ^ 1].f += tmp;
    				if (!lim) break;
    			}
    		}
    		return flow;
    	}
    	
    	int Dinic (int s, int t) {
    		int max_flow = 0;
    		while (bfs (s, t)) {
    			max_flow += dfs (s, t, INF);
    		}
    		return max_flow;
    	}
    }G;
    
    int n, m, _ans, id[N];
    
    struct Query {
    	int u, v;
    	
    	bool operator < (Query rhs) const {
    		return u == rhs.u ? v < rhs.v : u < rhs.u;
    	}	
    	
    	bool operator == (Query rhs) const {
    		return u == rhs.u && v == rhs.v;
    	}
    }q[N], ans[N];
    
    int A (int x) {return n * 0 + x;}
    int B (int x) {return n * 1 + x;}
    
    int read () {
    	int s = 0, w = 1, ch = getchar ();
    	while ('9' < ch || ch < '0') {
    		if (ch == '-') w = -1;
    		ch = getchar ();
    	}
    	while ('0' <= ch && ch <= '9') {
    		s = s * 10 + ch - '0';
    		ch = getchar ();
    	}
    	return s * w;
    } 
    
    stack <int> sta;
    int dfn[N], low[N], col[N], vis[N]; 
    
    void Tarjan (int u) {
    	sta.push (u);
    	vis[u] = true;
    	dfn[u] = low[u] = ++dfn[0];	
    	for (int i = G.head[u]; ~i; i = G.e[i].nxt) {
    		int v = G.e[i].to;
    		if (!G.e[i].f) continue;
    		if (!dfn[v]) {
    			Tarjan (v);
    			low[u] = min (low[u], low[v]);
    		} else if (vis[v]) {
    			low[u] = min (low[u], dfn[v]);
    		}
    	}
    	if (dfn[u] == low[u]) {
    		int tmp; ++col[0];
    		do {
    			tmp = sta.top ();
    			vis[tmp] = false;
    			col[tmp] = col[0];
    			sta.pop ();
    		}while (tmp != u);
    	}
    }
    
    
    int main () {
    	cin >> n >> m;
    	int s = n * 2 + 1;
    	int t = n * 2 + 2;
    	for (int i = 1; i <= m; ++i) {
    		q[i].u = read ();
    		q[i].v = read ();
    		if (q[i].u > q[i].v) {
    			swap (q[i].u, q[i].v);
    		}
    	}
    	sort (q + 1, q + 1 + m);
    	for (int i = 1; i <= m; ++i) {
    		id[i] = G.cnt + 1;
    		G.add_len (A (q[i].u), B (q[i].v), 1);
    		G.add_len (A (q[i].v), B (q[i].u), 1);
    	}
    	for (int i = 1; i <= n; ++i) {
    		G.add_len (s, A (i), 1);
    		G.add_len (B (i), t, 1);
    	}
    	G.Dinic (s, t);
    	for (int i = 1; i <= t; ++i) {
    		if (!dfn[i]) {
    			Tarjan (i);
    		}
    	}
    	for (int i = 1; i <= m; ++i) {
    		if (col[A (q[i].u)] != col[B (q[i].v)] && !G.e[id[i]].f) {
    			ans[++_ans] = q[i];
    		}
    	}
    	cout << _ans << endl;
    	for (int i = 1; i <= _ans; ++i) {
    		printf ("%d %d
    ", ans[i].u, ans[i].v);
    	}
    }
    
  • 相关阅读:
    剑指offer--38.左旋转字符串
    剑指offer--37.和为S的两个数字
    剑指offer--35.数组中只出现一次的数字
    剑指offer--34.数字在排序数组中出现的次数
    剑指offer--33.丑数
    SSIS包定时执行
    在SSIS 的 64 位版本中不支持 Excel 连接管理器[转]
    sql中的sp_helptext、sp_help 、sp_depends
    SQL去除回车符,换行符,空格和水平制表符
    SQL Server中bcp命令的用法以及数据批量导入导出
  • 原文地址:https://www.cnblogs.com/maomao9173/p/10638348.html
Copyright © 2020-2023  润新知