zoukankan      html  css  js  c++  java
  • 题解 最大获利

    题目传送门

    题目大意

    给出 (n) 个用户,(m) 个基站,每个用户的需求为用 (a,b) 两个基站,会产生 (c) 的收益。修基站也需要花费。问最大收益。

    (nle 5000,mle 50000)

    思路

    这个东西要用一个叫做最大权闭合子图的东西。大概意思就是求解,对于一个图,每个点有点权,你选了一个点则它的后继都必须选,问选出来的点权值之和最大是多少。对于这个问题我们可以最小割来做,(s) 往所有点权为正的点连,流量为点权,所有点权为负的点往 (t) 连,流量为点权绝对值。原图上的边流量改为 (infty)。然后答案就是所有边权为正的权值之和-最小割。

    这个模型的含义就是:

    对于 (s) 连向的点,如果割了这个边,相同于不选。

    对于连向 (t) 的点,如果割了这个边,相当于选。

    正确性和最优性应该显然,应该每个方案都与原图上的方案一一对应。

    对于这个点,我们可以直接用户连向基站就好了,用户点权为收益,基站点权为-花费。然后直接套用上面的最大权闭合子图即可。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define INF 0x3f3f3f3f
    #define MAXM 500005
    #define MAXN 60005
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,m,P[MAXN];
    
    struct edge{
    	int v,flw,nxt;
    }e[MAXM];
    int toop = 1,S,T,dep[MAXN],cur[MAXN],head[MAXN];
    void Add_Edge (int u,int v,int w){
    	e[++ toop] = edge {v,w,head[u]},head[u] = toop;
    	e[++ toop] = edge {u,0,head[v]},head[v] = toop;
    }
    
    bool BFS (){
    	memset (dep,0,sizeof (dep));	
    	queue <int> q;q.push (S),dep[S] = 1;
    	while (!q.empty()){
    		int u = q.front();q.pop ();
    		for (Int i = head[u];i;i = e[i].nxt){
    			int v = e[i].v,w = e[i].flw;
    			if (!dep[v] && w) dep[v] = dep[u] + 1,q.push (v);
    		}
    	}
    	return dep[T];
    }
    
    int dfs (int u,int flow){
    	if (u == T) return flow;
    	int ans = 0;
    	for (Int &i = cur[u];i && flow;i = e[i].nxt){
    		int v = e[i].v,f = e[i].flw;
    		if (dep[v] != dep[u] + 1) continue;
    		int res = dfs (v,min (flow,f));e[i].flw -= res,e[i ^ 1].flw += res,ans += res,flow -= res;
    	}
    	if (!flow) dep[u] = 0;
    	return ans;
    }
    
    int MinCut (){
    	int res = 0;
    	while (BFS ()){
    		memcpy (cur,head,sizeof (head));
    		res += dfs (S,INF);
    	}
    	return res;
    }
    
    signed main(){
    	read (n,m),S = n + m + 1,T = n + m + 2;
    	for (Int i = 1;i <= n;++ i) read (P[i]),Add_Edge (m + i,T,P[i]);int ans = 0;
    	for (Int i = 1,a,b,c;i <= m;++ i) read (a,b,c),Add_Edge (i,m + a,INF),Add_Edge (i,m + b,INF),Add_Edge (S,i,c),ans += c;
    	write (ans - MinCut()),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    RDIFramework.NET开发实例━表约束条件权限的使用-WinForm
    RDIFramework.NET V2.8版本 ━ 开发实例之产品管理(WinForm)
    RDIFramework.NET ━ Web中打印的各种方案参考-欢迎补充
    RDIFramework.NET 框架兼容各种数据库类型事务使用范例参考
    【干货】再上数据分页控件 ━ 更加灵活,更加实用-提供源码
    RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本━新增岗位管理-Web部分
    RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本━新增岗位管理-WinForm部分
    RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本发布
    Javascript中的apply与call详解
    Javascript定义类(class)的三种方法
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14008239.html
Copyright © 2011-2022 走看看