• [不知道哪来的题] 完美理论


    Description

    两棵点集相同的树,每个点有一个权值 (a[i](|a[i]|le 1000)) ,编号 (1) ~ (n(nle 100)) 。找到一个点集的子集使得这个子集在两棵树上都是连通块。输出最大的权值和。多组数据, (Tle 50)

    Solution

    考虑枚举两棵树的根 (root) ,则对于任意一个点,选了它就必须选它的父亲。

    这就是一个最大权闭合图的模型了。

    #include<bits/stdc++.h>
    using namespace std;
    
    template <class T> inline void read(T &x) {
    	x = 0; T flag = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') flag = -1;
    	for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0'; x *= flag;
    }
    
    #define N 250
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define INF 0x3f3f3f3f
    
    int S, T, head[N], cur[N], tot = 1, q[N], dep[N];
    struct edge { int v, c, next; }e[1001];
    inline void insert(int u, int v, int c) { e[++tot].v = v, e[tot].c = c, e[tot].next = head[u]; head[u] = tot; }
    inline void add(int u, int v, int c) { insert(u, v, c), insert(v, u, 0); }
    inline bool bfs() {
    	memset(dep, 0, sizeof dep); dep[S] = 1;
    	int l = 1, r = 1; q[1] = S;
    	while (l <= r) {
    		int u = q[l++];
    		for (int i = head[u], v; i; i = e[i].next) if (e[i].c && !dep[v = e[i].v]) {
    			dep[v] = dep[u] + 1, q[++r] = v;
    			if (!(v ^ T)) return 1;
    		}
    	}
    	return 0;
    }
    int dfs(int u, int dist) {
    	if (u == T) return dist;
    	int ret = 0;
    	for (int &i = head[u], v; i; i = e[i].next) if (dep[v = e[i].v] == dep[u] + 1 && e[i].c) {
    		int d = dfs(v, min(dist - ret, e[i].c));
    		e[i].c -= d, e[i ^ 1].c += d, ret += d;
    		if (ret == dist) return dist;
    	}
    	if (!ret) dep[u] = -1;
    	return ret;
    }
    inline void cpy() { rep(i, S, T) cur[i] = head[i]; }
    inline void rec() { rep(i, S, T) head[i] = cur[i]; }
    int dinic() { int ret = 0; cpy(); while (bfs()) ret += dfs(S, INF), rec(); return ret; }
    
    int n, tHead[N], tTot, a[N];
    struct tEdge { int v, next; }tE[1001];
    inline void tAdd(int u, int v) { tE[++tTot].v = v, tE[tTot].next = tHead[u], tHead[u] = tTot; }
    
    void dfs(int u, int fa, int t) {
    	for (int i = tHead[u]; i; i = tE[i].next) if (tE[i].v ^ fa)
    		add(tE[i].v - n * t, u - n * t, INF), dfs(tE[i].v, u, t);
    }
    
    int main() {
    	int Case; read(Case);
    	while (Case--) {
    		memset(tHead, 0, sizeof tHead); tTot = 0;
    		read(n); T = n + 1;
    		rep(i, 1, n) read(a[i]);
    		rep(i, 2, n) {
    			int u, v; read(u), read(v);
    			tAdd(u, v), tAdd(v, u);
    		}
    		rep(i, 2, n) {
    			int u, v; read(u), read(v);
    			tAdd(u + n, v + n), tAdd(v + n, u + n);
    		}
    		int ans = 0;
    		rep(i, 1, n) {
    			memset(head, 0, sizeof head); tot = 1;
    			int sum = 0;
    			dfs(i, 0, 0), dfs(i + n, 0, 1);
    			rep(j, 1, n)
    				if (a[j] > 0) sum += a[j], add(S, j, a[j]);
    				else add(j, T, -a[j]);
    			ans = max(ans, sum - dinic());
    		}
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    网络故障排除工具 | 快速定位网络故障
    Brocade博科光纤交换机zone配置
    博科Brocade 300光纤交换机配置zone教程
    游戏开发
    第8章 图
    第7章 二叉树
    第6章 树型结构
    第5章 递归
    第4章 字符串、数组和特殊矩阵
    第3章 顺序表的链式存储
  • 原文地址:https://www.cnblogs.com/aziint/p/9198001.html
Copyright © 2020-2023  润新知