zoukankan      html  css  js  c++  java
  • [最大权闭合子图小练]

    [POJ 2987]每个人都为公司带来一个收益,公司老板要裁员(当然是业绩不好给公司带来负收益的人被裁掉啦~),然而踢走一个人会把他的下属都踢走,求最大收益

    最大权闭合子图~,其实就是最小割啦,此题要求最小化走的人数,然而就是最小割中的人数QAQ(并不知道为什么),dfs(S)相关的点

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define maxn 100010
    using namespace std;
    
    typedef long long ll;
    
    const int inf = 0x7fffffff;
    
    int n, m;
    
    struct Edge{
    	int to, next, w;
    	Edge(int v = 0, int nxt = 0, int d = 0){
    		to = v, next = nxt, w = d;
    	}
    }edge[maxn * 5];
    int h[maxn], cnt = 1, S, T;
    
    void add(int u, int v, int w){
    	edge[++ cnt] = Edge(v, h[u], w); h[u] = cnt;
    	edge[++ cnt] = Edge(u, h[v], 0); h[v] = cnt;
    }
    
    queue<int> Q;
    
    int d[70000];
    
    bool BFS(){
    	memset(d, -1, sizeof d);
    	d[S] = 0; Q.push(S);
    	while(!Q.empty()){
    		int u = Q.front(); Q.pop();
    		for(int i = h[u]; i; i = edge[i].next){
    			if(!edge[i].w)continue;
    			int v = edge[i].to;
    			if(d[v] == -1) d[v] = d[u] + 1, Q.push(v);
    		}
    	}return d[T] != -1;
    }
    
    int cur[maxn];
    
    ll DFS(int x, ll a){
    	if(x == T || a == 0)
    	    return a;
    	int used = 0, f;
    	for(int i = cur[x]; i; i = edge[i].next){
    		int v = edge[i].to;
    		if(d[v] == d[x] + 1 && edge[i].w){
    			f = DFS(v, min(a-used, (ll)edge[i].w));
    			edge[i].w -= f;
    			edge[i^1].w += f;
    			used += f;
    			if(f > 0)cur[x] = i;
    			if( used == a)return used;
    		}
    	}
    	if(used == 0)d[x] = -1;
    	return used;
    }
    
    ll Dinic(){
    	ll ret = 0;
    	while(BFS()){
    		for(int i = S; i <= T; i ++)
    		    cur[i] = h[i];
    		ret += DFS(S, inf);
    	}
    	return ret ;
    }
    
    bool vis[maxn];
    
    void dfs(int u){
    	vis[u] = true;
    	for(int i = h[u]; i; i = edge[i].next){
    		int v = edge[i].to;
    		if(edge[i].w && !vis[v])
    		    dfs(v);
    	}
    }
    
    int main(){
    	scanf("%d%d", &n, &m);
    	S = 0, T = n + m + 1;
    	int b;
    	
    	ll sum = 0;
     	for(int i = 1; i <= n; i ++){
    		scanf("%d", &b);
    		if(b > 0){
    			add(S, i, b);
    			sum += b;
    		}
    		else add(i, T, -b);
     	}
     	int u, v;
     	for(int i = 1; i <= m; i ++){
    		scanf("%d%d", &u, &v);
    		add(u, v, inf);
     	}
     	sum -= Dinic();
     	dfs(S);
     	int ans = 0;
     	for(int i = 1; i <= n; i ++)
     	    ans += vis[i];
     	printf("%d %lld
    ", ans, sum);
    	return 0;
    }
    

    [HDU 3879]建立一个新站点需要Pi的花费,给定m个客户使用两个站点所带来的收益Ci,最大化收益

    把每一个客户新建一个点然后建图QAQ,不能在原图上直接连边。。只贴建图了QAQ。。

    while(scanf("%d%d", &n, &m) == 2){
    	memset(h, 0, sizeof h); cnt = 1;
    	int p; S = 0, T = n + m + 1;
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &p);
    		add(S, i, p);
    	}
    	int u, v, w, sum = 0, size = n;
    	for(int i = 1; i <= m; i ++){
    		scanf("%d%d%d", &u, &v, &w);
    		++ size;
    		add(u, size, inf);
    		add(v, size, inf);
    		add(size, T, w);
    		sum += w;
    	}
    	printf("%d
    ", sum - Dinic());
    }
    

    [HDU 4971]

    The first line of the input is a single integer T(<=100) which is the number of test cases.

    Each test case contains a line with two integer n(<=20) and m(<=50) which is the number of project to select to complete and the number of technical problem.

    Then a line with n integers. The i-th integer(<=1000) means the profit of complete the i-th project.

    Then a line with m integers. The i-th integer(<=1000) means the cost of training to solve the i-th technical problem.

    Then n lines. Each line contains some integers. The first integer k is the number of technical problems, followed by k integers implying the technical problems need to solve for the i-th project.

    After that, there are m lines with each line contains m integers. If the i-th row of the j-th column is 1, it means that you need to solve the i-th problem before solve the j-th problem. Otherwise the i-th row of the j-th column is 0.

    就是有问题和工程,解决问题是有关联性的而且要花费代价,解决一些问题可以去做某工程带来一些收益,求最大化收益

    最重要的是建图啦。。

    for(int dir = 1; dir <= test; dir ++){
    	memset(h, 0, sizeof h);
    	int sum = 0, p, k;
    	scanf("%d%d", &n, &m);
    	cnt = 1, S = 0, T = n + m + 1;
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &p);
    		add(S, i, p);
    		sum += p;
    	}
    
    	for(int i = 1; i <= m; i ++){
    		scanf("%d", &p);
    		add(i + n, T, p);
    	}
    
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &k);
    		for(int j = 1; j <= k; j ++){
    			scanf("%d", &p); p ++;
    			add(i, p + n, inf);
    		}
    	}
    
    	for(int i = 1; i <= m; i ++){
    		for(int j = 1; j <= m; j ++){
    			scanf("%d", &p);
    			if(p == 1) add(i + n, j + n, inf);
    		}
    	}
    	printf("Case #%d: %d
    ", dir, sum - Dinic());
    }
    

    vfk once said

    我们来回忆一下最小割。如果v向u连一条容量为w的有向边,表示v如果在S割,那么u不在S割会产生w的代价。
    一个等价的表述是,u如果在T割,那么v不在T割会产生w的代价。
    注意v如果在T割,那么u在S割是不会产生代价的。
    特别的,如果v向u连一条容量为正无穷大的有向边,表示v如果在S割,那么u一定也要在S割。
    一个等价的表述是,u如果在T割,那么v一定也要在T割。
     
    总结一下就是选择一个点可以选或者必须选某个点,可以用最大权闭合子图来解决。
    给时光以生命,而不是给生命以时光。
  • 相关阅读:
    BZOJ1610: [Usaco2008 Feb]Line连线游戏
    BZOJ4554: [Tjoi2016&Heoi2016]游戏
    BZOJ3174: [Tjoi2013]拯救小矮人
    BZOJ3192: [JLOI2013]删除物品
    BZOJ3156: 防御准备
    BZOJ3875: [Ahoi2014&Jsoi2014]骑士游戏
    BZOJ 1597: [Usaco2008 Mar]土地购买
    洛谷 P3375 【模板】KMP字符串匹配
    洛谷 P3370 【模板】字符串哈希
    BZOJ 1083 繁忙的都市
  • 原文地址:https://www.cnblogs.com/Candyouth/p/5349123.html
Copyright © 2011-2022 走看看