zoukankan      html  css  js  c++  java
  • bzoj2163 复杂的大门

    Description

    你去找某 bm 玩,到了门口才发现要打开他家的大门不是一件容易的事……

    他家的大门外有 (n) 个站台,用 (1)(n) 的正整数编号。你需要对每个站台访问一定次数以后大门才能开启。站台之间有 (m) 个单向的传送门,通过传送门到达另一个站台不需要花费任何代价。而如果不通过传送门,你就需要乘坐公共汽车,并花费 (1) 单位的钱。值得庆幸的是,任意两个站台之间都有公共汽车直达。

    现在给你每个站台必须访问的次数 (F_i) ,对于站台 (i) ,你必须恰好访问 (F_i) 次(不能超过)。

    我们用 (u)(v)(w) 三个参数描述一个传送门,表示从站台 (u) 到站台 (v) 有一个最多可以使用 (w) 次的传送门(不一定要使用 (w) 次)。值得注意的是,对于任意一对传送门 ((u_1,v_1))
    ((u_2,v_2)) ,如果有 (u_1<u_2) ,则有 (v_1le v_2) ;如果有 (v_1<v_2) ,则有 (u_1le u_2) ;且 (u_1=u_2)(v_1=v_2) 不同时成立。

    你可以从任意的站台开始,从任意的站台结束。出发去开始的站台需要花费 (1) 单位的钱。你需要求出打开大门最少需要花费多少单位的钱。

    Input

    第一行包含两个正整数 (n)(m) ,意义见题目描述。第二行包含 (n) 个正整数,第 (i) 个数表示 (F_i) 。接下来有 (m) 行,每行有三个正整数 (u)(v)(w) ,表示从 (u)(v) 有一个可以使用 (w) 次的传送门。

    Output

    输出一行一个整数,表示打开大门最少花费的钱数。

    Sample Input

    4 3
    5 5 5 5
    1 2 1
    3 2 1
    3 4 1
    

    Sample Output

    17
    

    HINT

    (100\%) 的数据满足 (1le nle 10000)(1≤m≤100000)

    对于所有的 (u)(v) ,满足 (1≤u,v≤n)(u≠v) ;对于所有的 (w)(F_i) ,满足 (1≤w,Fi≤50000)

    以上的每类数据中都存在 (50\%) 的数据满足对于所有的 (w)(F_i) ,有 (w=F_i=1)

    Soution

    最开始想的是要把每个公交车都体现在图上,发现会有 (n^2) 条边,跪了。

    想了想,可以把问题转换为最多使用多少次传送门,这样就可以把公交车的连边问题略去了。

    考虑拆点。点 (x) 拆成 (x_1)(x_2) 。考虑连边 $$<S, x_1>:capacity=F[x]$$ $$<x_2,T>:capacity=F[x]$$ $$<x_1,y_2>:capacity=w$$

    最后答案就是 $$sum_{i=1}^nF[i] - maxFlow$$

    #include<bits/stdc++.h>
    using namespace std;
    
    #define N 20001
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define INF 2000000000
    
    inline int read() {
    	int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
    }
    
    int n, m, sum;
    
    int S, T;
    struct edge { int v, c, next; }e[220001];
    int head[N], tot = 1;
    int q[N], dep[N];
    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) || !dist) return dist;
    	int ret = 0;
    	for (int i = head[u], v, c; i; i = e[i].next) if ((c = e[i].c) && !(dep[v = e[i].v] ^ (dep[u] + 1))) {
    		int d = dfs(v, min(dist, c));
    		dist -= d, ret += d, e[i].c -= d, e[i ^ 1].c += d;
    		if (!dist) break;
    	}
    	return ret;
    }
    int dinic() { int ret = 0; while (bfs()) ret += dfs(S, INF); return ret; }
    
    int main() {
    	n = read(), m = read(); T = 2 * n + 1;
    	rep(i, 1, n) { int f = read(); add(S, i, f), add(i + n, T, f); sum += f; }
    	rep(i, 1, m) { int u = read(), v = read(), c = read(); add(u, v + n, c); }
    	printf("%d", sum - dinic());
    	return 0;
    }
    
  • 相关阅读:
    JQuery Ajax 的简单使用
    使用PHP QR Code生成二维码
    SQL中Group By的使用
    虚拟主机的配置
    文件上传
    session机制详解以及session的相关应用
    thinkphp权限管理Rbac实例
    jQuery处理点击父级checkbox所有子级checkbox都选中,取消选中所有子级checkbox都取消
    传递一个父id返回所有子id的用法,可用于删除父级以下的所有子级
    thinkphp3.2独立分组的建立
  • 原文地址:https://www.cnblogs.com/aziint/p/8457779.html
Copyright © 2011-2022 走看看