您的位置:首页 > 其它

hdu 3879 Base Station bzoj 1497 最大获利问题 最大权闭合子图

2016-02-29 11:33 253 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3879

http://www.lydsy.com/JudgeOnline/problem.php?id=1497

题意:

在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)

思路:

经典的最大权闭合子图问题。

因为用户通过使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。即满足这个用户群,就可以得到收益c。

但是获得收益C需要一个必要条件:建立中转站a和b,需要花去一定的费用,这就是满足了闭合图的性质。

所以按照最大权闭合子图的方法来建图。

建立超级源点s和超级汇点t。

s向每个收益点连一条边,容量为ci。

每个站点向t连一条边,容量为pi。

每个需要a, b, i中 i分别向a和b连一条边,容量为inf。

然后求最小割。

答案就是正权点总权和 - 最小割。

//#include <bits/stdc++.h>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
struct Edge
{
int from, to, cap, flow;
Edge(int f, int t, int c, int fl)
{
from = f; to = t; cap = c; flow = fl;
}
};
#define maxn 55010
#define inf 0x3f3f3f3f
vector <Edge> edges;
int n, m, s, t;
vector <int> G[maxn];
int d[maxn], vis[maxn], cur[maxn];
void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs()
{
memset(vis, 0, sizeof(vis));
d[s] = 0; vis[s] = 1;
queue <int> q; q.push(s);
while(!q.empty())
{
int x = q.front(); q.pop();
for(int i = 0; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow)
{
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x, int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(d[e.to] == d[x]+1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int maxflow()
{
int flow = 0;
while(bfs())
{
memset(cur, 0, sizeof(cur));
flow += dfs(s, inf);
}
return flow;
}
int N, M;
int p[5050];
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
while(~scanf("%d%d", &N, &M))
{
edges.clear();
s = 0; t = N+M+1; n = N+M+2;
for(int i = 0; i <= t; i++) G[i].clear();
for(int i = 1; i <= N; i++)
{
scanf("%d", &p[i]);
AddEdge(i+M, t, p[i]);
}
int sum = 0;
for(int i = 1; i <= M; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
sum += c;
AddEdge(s, i, c);
AddEdge(i, a+M, inf);
AddEdge(i, b+M, inf);
}
int flow = maxflow();
printf("%d\n", sum-flow);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: