题目大意是:在N个点中选取某些点,使得这些点的权值和最大,每个点的权值可能存在负数,并且某些点之间存在约束关系,例如:当选取A点时,B点也必须同时选中,则A与B之间有边(单向)。顶点N最多5000,边数最多60000。
这一类问题属于最大权闭合图,引入两个顶点,源点S,汇点T,将权值为正的点同S相连,容量为该权值;为负的同T相连,容量为权值的绝对值;对于顶点之间有边的,则将其容易定为无穷大;这里有一个结论:最大权闭合子图的权值和W = K - C,其中K为所有权值为正的之和,C为该图的最小割容量,至于证明,这里不再描述。贴上代码。
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <string.h>
#include <string>
#include <iostream>
#include <queue>
#include <list>
#include <algorithm>
#include <stack>
#include <map>
#include<iostream>
#include<cstdio>
using namespace std;
#define INF 10000000000LL
#define min(a,b) (((a) < (b)) ? (a) : (b))
typedef int MYTYPE;
struct Edge
{
int to;
int cap;
int i;
};
//MYTYPE G[5002][5002];
vector<Edge> G[5002];
int Level[5002];
void AddEdge(int from, int to, int cap)
{
Edge edge;
edge.to = to;
edge.cap = cap;
edge.i = G[to].size();
G[from].push_back(edge);
edge.to = from;
edge.cap = 0;
edge.i = G[from].size() - 1;
G[to].push_back(edge);
}
int bfs(int s, int n)
{
int count = 0;
memset(Level, -1, sizeof(Level));
queue<int> que;
Level[s] = 0;
que.push(s);
while (!que.empty())
{
count++;
int v = que.front();
que.pop();
for (int i = 0; i < G[v].size(); i++)
{
Edge& edge = G[v][i];
if (G[v][i].cap > 0 && Level[edge.to] < 0)
{
Level[edge.to] = Level[v] + 1;
que.push(edge.to);
}
}
}
return count;
}
MYTYPE dfs(int from, int to, int k, int n)
{
if (from == to)
{
return k;
}
for (int i = 0; i < G[from].size(); i++)
{
Edge& edge = G[from][i];
if (Level[from] < Level[edge.to] && G[from][i].cap > 0)
{
MYTYPE d = dfs(edge.to, to, min(G[from][i].cap, k), n);
if (d > 0)
{
int tmp = G[from][i].i;
G[from][i].cap -= d;
G[edge.to][tmp].cap += d;
return d;
}
}
}
return 0;
}
int main()
{
#ifdef _DEBUG
freopen("e:\\in.txt", "r", stdin);
#endif
int n, m;
scanf("%d %d", &n, &m);
//memset(G, 0, sizeof(G));
// memset(Head, 0, sizeof(Head));
long long totalvalue = 0;
for (int i = 1; i <= n; i++)
{
int value;
scanf("%d", &value);
if (value > 0)
{
//G[0][i] = value;
AddEdge(0, i, value);
totalvalue += value;
}
else
{
//G[i][n + 1] = -value;
AddEdge(i, n + 1, -value);
}
}
for (int i = 0; i < m; i++)
{
int s, t;
scanf("%d %d", &s, &t);
//G[s][t] = INF;
AddEdge(s, t, INF);
}
long long f = 0;
int count = 0;
for (;;)
{
count = bfs(0, n + 2) - 1;
if (Level[n + 1] < 0)
{
break;
}
MYTYPE d;
while ((d = dfs(0, n + 1, INF, n + 2)) > 0)
{
f += (long long)d;
}
}
printf("%d %I64d\n", count, totalvalue - f);
return 0;
}