zoukankan      html  css  js  c++  java
  • day23T1改错记

    题目描述

    两颗点集相同的树(点编号(1)~(n)),每个点有一个权值(a_i),你要选出一个点集的子集,这个点集的点在两棵树上都是一个联通块,求选出的点集的权值和最大值

    多组数据,数据组数为(T)

    (T le 50, n le 100, |a_i| le 1000)

    解析

    直接考虑联通块不方便,不妨枚举某个点一定被选的情况

    枚举必选点(i),那么如果选了另外的某个点(j)(i)(j)路径上的点也要选

    (i)置为树根,那么如果选(j)(j)在两棵树上的父亲也要选

    于是把每个点(j)向两个父亲连边,问题变成了最大权闭合子图

    多组数据(O(T)),枚举树根(O(n)),最大流(O(n^2m) = O(n^2 cdot 3n) = O(n^3))

    所以总复杂度(O(Tn^4)),怎么看都过不了但是实际上跑得还不慢???

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAXN 105
    
    typedef long long LL;
    const int inf = 0x3f3f3f3f;
    struct Graph {
    	struct Edge {
    		int v, next, cap;
    		Edge(int _v = 0, int _n = 0, int _c = 0):v(_v), next(_n), cap(_c) {}
    	} edge[MAXN << 4];
    	int head[MAXN << 1], cur[MAXN << 1], cnt, dep[MAXN << 1];
    	void init() { memset(head, -1, sizeof head); cnt = 0; }
    	void add_edge(int u, int v, int c) { edge[cnt] = Edge(v, head[u], c); head[u] = cnt++; }
    	void insert(int u, int v, int c) { add_edge(u, v, c); add_edge(v, u, 0); }
    	bool bfs();
    	int dfs(int, int);
    	int dinic();
    };
    struct Tree {
    	struct Edge {
    		int v, next;
    		Edge(int _v = 0, int _n = 0):v(_v), next(_n) {}
    	} edge[MAXN << 1];
    	int head[MAXN], fa[MAXN], cnt;
    	void init() { memset(head, -1, sizeof head); cnt = 0; }
    	void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; }
    	void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }
    	void dfs(int, int);
    };
    
    void build(int, int);
    
    Graph G;
    Tree t1, t2;
    int N, T, val[MAXN], ans, sum;
    
    int main() {
    	scanf("%d", &T);
    	while (T--) {
    		t1.init(), t2.init();
    		ans = sum = 0;
    		scanf("%d", &N);
    		for (int i = 1; i <= N; ++i) {
    			scanf("%d", val + i);
    			if (val[i] > 0) sum += val[i];
    		}
    		for (int i = 1; i < N; ++i) {
    			int u, v; scanf("%d%d", &u, &v);
    			t1.insert(u, v);
    		}
    		for (int i = 1; i < N; ++i) {
    			int u, v; scanf("%d%d", &u, &v);
    			t2.insert(u, v);
    		}
    		for (int i = 1; i <= N; ++i) {
    			G.init();
    			t1.dfs(i, 0), t2.dfs(i, 0);
    			for (int j = 1; j <= N; ++j) {
    				if (j ^ i) G.insert(j, t1.fa[j], inf), G.insert(j, t2.fa[j], inf);
    				if (val[j] > 0) G.insert(0, j, val[j]);
    				else G.insert(j, N + 1, -val[j]);
    			}
    			ans = std::max(ans, sum - G.dinic());
    		}
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    }
    bool Graph::bfs() {
    	memset(dep, 0, sizeof dep);
    	static int que[MAXN << 1], hd, tl;
    	hd = tl = 0;
    	que[tl++] = 0, dep[0] = 1;
    	while (hd < tl) {
    		int p = que[hd++];
    		if (p == N + 1) break;
    		for (int i = head[p]; ~i; i = edge[i].next)
    			if (edge[i].cap && !dep[edge[i].v]) {
    				dep[edge[i].v] = dep[p] + 1;
    				que[tl++] = edge[i].v;
    			}
    	}
    	return dep[N + 1];
    }
    int Graph::dfs(int u, int maxflow) {
    	if (u == N + 1) return maxflow;
    	int res = 0;
    	for (int &i = cur[u]; ~i; i = edge[i].next)
    		if (edge[i].cap && dep[edge[i].v] == dep[u] + 1) {
    			int d = dfs(edge[i].v, std::min(maxflow, edge[i].cap));
    			if (d) {
    				edge[i].cap -= d, edge[i ^ 1].cap += d;
    				res += d, maxflow -= d;
    				if (!maxflow) break;
    			}
    		}
    	if (!res) dep[u] = -1;
    	return res;
    }
    int Graph::dinic() {
    	int res = 0;
    	while (bfs()) {
    		memcpy(cur, head, sizeof head);
    		res += dfs(0, inf);
    	}
    	return res;
    }
    void Tree::dfs(int u, int f) {
    	fa[u] = f;
    	for (int i = head[u]; ~i; i = edge[i].next)
    		if (edge[i].v ^ f) dfs(edge[i].v, u);
    }
    //Rhein_E 100pts
    
  • 相关阅读:
    (二)正反向代理
    (一)服务器架构详解
    斐波那契数列
    旋转数组的最小值
    23 入栈 出栈
    重建二叉树
    22 大端序和小端序
    反转单链表
    替换空格
    二维数组中的查找
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10601243.html
Copyright © 2011-2022 走看看