HDU3879:Base Station
——建通讯站。每个通讯站有一定耗费,两个特定的通讯站之间建立通讯以后会有一定收益,问怎样建立通讯站可以使得收益最大
——最大权闭合子图-》最小割
——url:http://acm.hdu.edu.cn/showproblem.php?pid=3879
——————————————————————————————————————————
首先考虑将图转化。
即一条通讯线路有一定收益,但需要建立两个通讯站,这两个通讯站有一定造价。
将通讯线路也变成点,点权为收益,连两条有向只向两个通讯站。
原来的通讯站点权不变。
由此,题目转化为在新的图中求一个闭合图,使得其点权最大,即最大权闭合子图
(闭合图个人理解的定义:对于点集中的所有点,其后继结点一定在该点集中)
——————————————————————————————————————————————
最大权闭合子图的求解参见IOI2007胡伯涛的论文。
新建一个源点S,S与每个通讯线路的点相连,边权为收益
新建一个汇点T,T与每个通讯站相连,边权为建造费用
通讯站与通讯线路之间的边权为无穷大
最后的结果为所有通讯线路总的收益-最小割
#include<stdio.h>
#include<memory.h>
#define N 56000
#define oo 0x7ffffff
int head[N], nxt[N * 10], ev[N*10],ew[N*10];
int pi[N], pe[N];
int CurrentNode[N];
int queue[N];
int d[N];
int numbs[N];
int n, m, node_sum, source, sink, ans, num;
void addedge(int u, int v, int w)
{
nxt[++num] = head[u];
head[u] = num;
ev[num] = v;
ew[num] = w;
nxt[++num] = head[v];
head[v] = num;
ev[num] = u;
ew[num] = 0;
}
void readin()
{
int i, a, b, c;
num = -1;
memset(head, -1, sizeof(head));
memset(nxt, -1, sizeof(nxt));
for (i = 1; i <= n; i++)
{
scanf("%d", &c);
addedge(i, n + m + 2, c);
}
node_sum = n;
ans = 0;
for (i = 0; i < m; i++)
{
node_sum++;
scanf("%d%d%d", &a, &b, &c);
addedge(node_sum, a, oo);
addedge(node_sum, b, oo);
addedge(n + m + 1, node_sum, c);
ans += c;
}
source = n + m + 1;
sink = n + m + 2;
node_sum = n + m + 2;
}
int Augment(int source, int sink)
{
int i, j, tmp, width(oo);
for (i = sink, j = pi[i]; i != source; i = j, j = pi[j])
{
tmp = ew[pe[i]];
if (tmp < width)
width = tmp;
}
for (i = sink, j = pi[i]; i != source; i = j, j = pi[j])
{
ew[pe[i]] -= width;
ew[pe[i] ^ 1] += width;
}
return width;
}
int Retreat(int &i, int n, int source, int sink)
{
int tmp;
int j, mind(n - 1);
for (j = head[i]; j != -1; j = nxt[j])
if (ew[j] > 0 && d[ev[j]] < mind)
mind = d[ev[j]];
tmp = d[i];
numbs[d[i]]--;
d[i] = 1 + mind;
numbs[d[i]]++;
if (i != source)
i = pi[i];
return numbs[tmp];
}
int find_max_flow(int n, int source, int sink)
{
int flow(0), i, j;
memset(d, 0, sizeof(d));
memset(numbs, 0, sizeof(numbs));
numbs[0] = n;
for (i = 1; i <= n; i++)
CurrentNode[i] = head[i];
i = source;
for (; d[source] < n;)
{
for (j = CurrentNode[i]; j != -1; j = nxt[j])
if (ew[j] > 0 && d[i] == d[ev[j]] + 1)
break;
if (j != -1)
{
CurrentNode[i] = j;
pi[ev[j]] = i;
pe[ev[j]] = j;
i = ev[j];
if (i == sink)
{
flow += Augment(source, sink);
i = source;
}
}
else
{
CurrentNode[i] = head[i];
if (Retreat(i, n, source, sink) == 0)
break;
}
}
return flow;
}
int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
readin();
ans -= find_max_flow(node_sum, source, sink);
printf("%d\n", ans);
}
return 0;
}
浙公网安备 33010602011771号