Hdu3947 流量等式建图

此题是以《NOI2008志愿者招募》为背景的,预做此题需要先体会《志愿者招募》的思想

只不过由线性结构变为树形结构,但是问题的本质没有变,都是一个元素影响连续的若干个位置,构图的本质都是使每个变量x出现分别以+和-的形式出现在两个恒等式中,由此可以看做x变量从+式流入-式流出。设药品为x,为每条河建立一个等式,则x出现在了u的父边到v的父边路径上的所有等式中,因此用每个点的父边减去所有孩子的边(设根节点的父边为全0,即没有限制)得到n个等式,且所有变量x、y均以+和-的形式各出现一次,由此可以构图。若求出最大流==源点的最大容量则最小费用即为解,否则无解。

志愿者招募题解写的不错,体会一下x、y变量的作用应该就会构图了,构图如下:

class node {
		int be, ne;
		int id, val;
		node(int b, int e, int v) {
			be = b;
			ne = e;
			val = v;
		}
	}
	node buf[] = new node[maxn];
	int E[] = new int[maxn], len;
	void add(int a, int b, int v) {
		buf[len] = new node(b, E[a], v);
		id[b] = len;
		E[a] = len++;
	}
	Scanner scan = new Scanner(System.in);
	int n, m, id[] = new int[maxn], sum;
	boolean is[] = new boolean[maxn];
	MINCOST sp = new MINCOST();
	void init() {
		sp.init();
		len = 0;
		Arrays.fill(E, -1);
		Arrays.fill(is, true);
		sum = 0;
	}
	void run() {
		int cas = scan.nextInt();
		for (int k = 1; k <= cas; k++) {
			System.out.print("Case #" + k + ": ");
			n = scan.nextInt();
			init();
			int a, b, v;
			for (int i = 1; i < n; i++) {
				a = scan.nextInt();
				b = scan.nextInt();
				v = scan.nextInt();
				is[a] = false;
				add(b, a, v);
			}
			int root = -1;
			for (int i = 1; i <= n; i++)
				if (is[i]) {
					root = i;
					break;
				}
			id[root] = n - 1;
			int s, t, l, c;
			m = scan.nextInt();
			for (int i = 0; i < m; i++) {
				s = scan.nextInt();
				t = scan.nextInt();
				l = scan.nextInt();
				c = scan.nextInt();
				sp.addcap(id[s], id[t], l, c);
			}
			int temp = 0;
			for (int i = E[root]; i != -1; i = buf[i].ne) {
				temp += buf[i].val;
				sp.addcap(n - 1, i, inf, 0);
				dfs(i);
			}
			sp.addcap(n - 1, n + 1, temp, 0);
			int ans = sp.solve(n, n + 1);
			if (sp.maxflow == sum)
				System.out.println(ans);
			else
				System.out.println(-1);
		}
	}
	void dfs(int a) {
		int temp = buf[a].val;
		int v = buf[a].be;
		for (int i = E[v]; i != -1; i = buf[i].ne) {
			sp.addcap(a, i, inf, 0);
			temp -= buf[i].val;
			dfs(i);
		}
		if (temp > 0) {
			sp.addcap(n, a, temp, 0);
			sum += temp;
		} else
			sp.addcap(a, n + 1, -temp, 0);
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值