最大权闭合子图的模板题,就是读入还有输出方案比较恶心_(:з」∠)_
原图里的边容量设为∞,源S到正权点连容量为w的边,负权点到汇T连容量为-w的边。最小割的值和最大流的值相等,但它要输出方案,所以先求一遍最大流,然后从原点搜索,能走到(也包括通过反向边走到)的点打一个标记。一条边,如果他的两个端点一个打了标记,一个没打标记,那它就是一个割。
与源S相连的点(也就是实验Ei),所连的边不是割的是被选上的;与汇T相连的点,所连的边是割的是被选上的。
用vector存边遍历的时候要存它是哪个点的第几条边!!!!!
#include <cstdio>
#include <cmath>
#include <climits>
#include <algorithm>
#include <vector>
#include <queue>
#include <iostream>
#include <cstring>
#include <string>
#include <utility>
using namespace std;
const int MAXN = 100 + 5;
const int MAXM = 100 + 5;
struct Node {
vector<struct Edge> edges;
int level;
struct Edge *curE;
bool vis, choose;
} N[MAXN];
struct Edge {
Node *from, *to;
int flow, cap, rev;
bool isCut;
Edge (Node *from, Node *to, int cap, int rev) : from(from), to(to), flow(0), isCut(false), cap(cap), rev(rev) {}
};
vector<pair<int, int> > E;
inline int addEdge(int u, int v, int cap)
{
N[u].edges.push_back(Edge(&N[u], &N[v], cap, N[v].edges.size()));
N[v].edges.push_back(Edge(&N[v], &N[u], 0, N[u].edges.size() - 1));
return N[u].edges.size() - 1;
}
struct Dinic {
inline bool makeLevelGraph(Node *s, Node *t, int n)
{
for (int i = 0; i < n; i++)
{
N[i].curE = &N[i].edges.front();
N[i].level = 0;
}
queue<Node *> q;
q.push(s);
s->level = 1;
while (!q.empty())
{
Node *v = q.front();
q.pop();
for (Edge *e = &v->edges.front(); e && e <= &v->edges.back(); e++)
{
if (e->flow < e->cap && !e->to->level)
{
e->to->level = v->level + 1;
if (e->to == t) return true;
else q.push(e->to);
}
}
}
return false;
}
int findPath(Node *s, Node *t, int limit = INT_MAX)
{
if (s == t) return limit;
for (Edge *&e = s->curE; e && e <= &s->edges.back(); e++)
{
if (e->flow < e->cap && e->to->level == s->level + 1)
{
int flow = findPath(e->to, t, min(limit, e->cap - e->flow));
if (flow)
{
e->flow += flow;
e->to->edges[e->rev].flow -= flow;
return flow;
}
}
}
return 0;
}
int operator()(int s, int t, int n)
{
int res = 0;
while (makeLevelGraph(&N[s], &N[t], n))
{
int flow;
while ((flow = findPath(&N[s], &N[t])) > 0) res += flow;
//printf("flow = %d\n", flow);
}
return res;
}
} dinic;
void isCut(Node *s)
{
s->vis = true;
queue<Node *> q;
q.push(s);
while (!q.empty())
{
Node *v = q.front();
q.pop();
for (Edge *e = &v->edges.front(); e && e <= &v->edges.back(); e++)
{
if (e->flow < e->cap && !e->to->vis)
{
e->to->vis = true;
q.push(e->to);
}
}
}
for (int i = 0; i < (int)E.size(); i++)
{
if ((N[E[i].first].vis == true) && (N[E[i].first].edges[E[i].second].to->vis == false))
{
N[E[i].first].edges[E[i].second].isCut = true;
}
}
}
int main()
{
int n, m;
scanf("%d %d", &m, &n);
int S = 0, T = n + m + 1;
int sum = 0;
for (int i = 1; i <= m; i++)
{
int pay;
scanf("%d", &pay);
E.push_back(make_pair(S, addEdge(S, i, pay)));
sum += pay;
int x;
char ch = getchar();
while ((ch = getchar()) != '\n')
{
x = ch - '0';
while ((ch = getchar()) && ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
}
E.push_back(make_pair(i, addEdge(i, m + x, INT_MAX)));
if (ch == '\n') break;
}
}
for (int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
E.push_back(make_pair(i + m, addEdge(i + m, T, x)));
}
int cost = dinic(S, T, n + m + 2);
isCut(&N[S]);
// for (int i = 0; i < (int)E.size(); i++)
// {
// printf("%d %d\n", E[i].first, E[i].second);
// }
for (int i = 0; i < (int)E.size(); i++)
{
if (N[E[i].first].edges[E[i].second].isCut == true)
{
if (E[i].first == S) N[E[i].first].edges[E[i].second].to->choose = true;
if (int(N[E[i].first].edges[E[i].second].to - N) == T) N[E[i].first].choose = true;
}
}
for (int i = 1; i <= m; i++)
{
if (!N[i].choose) printf("%d ", i);
}
printf("\n");
for (int i = 1; i <= n; i++)
{
if (N[i + m].choose) printf("%d ", i);
}
printf("\n");
printf("%d\n", sum - cost);
return 0;
}