zoukankan      html  css  js  c++  java
  • [CF475E]Strongly Connected City 2

    题目大意:给一张$n(nleqslant2000)$个点的无向图,给所有边定向,使定向之后存在最多的有序点对$(a,b)$满足从$a$能到$b$

    题解:先把边双缩点,因为这里面的点一定两两可达。

    根据网上题解得知,最优解一定长这样:存在一个点$s$,使得对于任意其他点$t$,要么$s$可以到$t$,要么$t$可以到$s$,就把$s$作为根。(出题人的题解也没给出解答,就感性理解)

    所以$s$的每一个子树内的边要么都朝向$s$,要么都远离$s$

    然后可以枚举哪个点作为根,记$w_i$第$i$个双联通分量的大小,$sz_i$为以第$i$个双联通分量为根的子树大小,每个子树内的点在子树内的贡献为$w_i(sz_i-w_i)$,令$P$为朝向根的节点的$sz$和,过根的贡献为$P(n-w_s-P)$,所以只需要让$P$与$(n-w_s-P)$尽可能接近即可,可以用背包来实现

    卡点:

    C++ Code:

    #include <cstdio>
    #include <bitset>
    #define maxn 2010
    #define maxm (maxn * maxn)
    inline int min(int a, int b) {return a < b ? a : b;}
    inline int max(int a, int b) {return a > b ? a : b;}
    
    int n, m;
    
    namespace Graph {
    	int head[maxn], cnt = 1;
    	struct Edge {
    		int to, nxt;
    	} e[maxm];
    	inline void addE(int a, int b) {
    		e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    		e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
    	}
    	
    	int w[maxn];
    	int DFN[maxn], low[maxn], idx;
    	int S[maxn], top, res[maxn], scc;
    	void tarjan(int u, int fa = 0) {
    		DFN[u] = low[u] = ++idx;
    		S[++top] = u;
    		int v;
    		for (int i = head[u]; i; i = e[i].nxt) {
    			v = e[i].to;
    			if (v != fa) {
    				if (!DFN[v]) {
    					tarjan(v, u);
    					low[u] = min(low[u], low[v]);
    				} else low[u] = min(low[u], DFN[v]);
    			}
    		}
    		if (DFN[u] == low[u]) {
    			scc++;
    			do {
    				v = S[top--];
    				w[res[v] = scc]++;
    			} while (u != v);
    		}
    	}
    }
    
    long long ans;
    namespace Tree {
    	int head[maxn], cnt;
    	struct Edge {
    		int to, nxt;
    	} e[maxn << 1];
    	inline void addE(int a, int b) {
    		e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    		e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt;
    	}
    	using Graph::res;
    	using Graph::w;
    	using Graph::scc;
    	
    	void init(int n, int m) {
    		for (int i = 1; i <= n; i++) if (!Graph::DFN[i]) Graph::tarjan(i);
    		for (int i = 2; i <= Graph::cnt; i += 2) {
    			int u = Graph::e[i ^ 1].to, v = Graph::e[i].to;
    			if (res[u] != res[v]) addE(res[u], res[v]);
    		}
    	}
    
    	int sz[maxn];
    	int __ans, sumsz;
    	std::bitset<maxn / 2> B;
    	#define ans __ans
    	void dfs(int u, int fa = 0) {
    		sz[u] = w[u];
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			if (v != fa) {
    				dfs(v, u);
    				sz[u] += sz[v];
    			}
    		}
    		ans += sz[u] * w[u];
    	}
    	int calc(int u) {
    		B.reset();
    		B[0] = true;
    		ans = 0; dfs(u);
    		for (int i = head[u]; i; i = e[i].nxt) {
    			int v = e[i].to;
    			B |= B << sz[v];
    		}
    		for (int i = sumsz - w[u] >> 1; i; i--) if (B[i]) return ans + i * (sumsz - w[u] - i);
    		return ans;
    	}
    	#undef ans
    
    	int q[maxn], h, t;
    	bool vis[maxn];
    	void solve(int u) {
    		vis[q[h = t = 0] = u] = true;
    		int res = 0;
    		sumsz = 0;
    		while (h <= t) {
    			int u = q[h++];
    			sumsz += w[u];
    			for (int i = head[u]; i; i = e[i].nxt) {
    				int v = e[i].to;
    				if (!vis[v]) vis[q[++t] = v] = true;
    			}
    		}
    		for (int i = 0; i <= t; i++) res = max(res, calc(q[i]));
    		ans += res;
    	}
    	void work() {
    		for (int i = 1; i <= scc; i++) if (!vis[i]) solve(i);
    	}
    }
    
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 0, a, b; i < m; i++) {
    		scanf("%d%d", &a, &b);
    		Graph::addE(a, b);
    	}
    	Tree::init(n, m);
    	Tree::work();
    	printf("%lld
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    leetcode231 2的幂 leetcode342 4的幂 leetcode326 3的幂
    leetcode300. Longest Increasing Subsequence 最长递增子序列 、674. Longest Continuous Increasing Subsequence
    leetcode64. Minimum Path Sum
    leetcode 20 括号匹配
    算法题待做
    leetcode 121. Best Time to Buy and Sell Stock 、122.Best Time to Buy and Sell Stock II 、309. Best Time to Buy and Sell Stock with Cooldown 、714. Best Time to Buy and Sell Stock with Transaction Fee
    rand7生成rand10,rand1生成rand6,rand2生成rand5(包含了rand2生成rand3)
    依图
    leetcode 1.Two Sum 、167. Two Sum II
    从分类,排序,top-k多个方面对推荐算法稳定性的评价
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9928666.html
Copyright © 2011-2022 走看看