As all you know, DD is a hospitable person. On Saint Valentine's Day, DD is going to arrang a party for girls and boys. However, as you may don't know, DD hate the so-called "8g" relationship. So, he will not invite a boy and a girl who have 8g at the same time.
DD's friends are M boys (labeled 1..M) and N girls (labeled 1..N), and each of them has a "lovely value". Now, DD want to invite some of them, satisfying that no 8g exists among invited people, and the total lovely value of all the invited people can be maximal.
Input
Multiple test cases, each cases consists of three parts.
First part, one line, three integers M, N and S.
Second part, two lines. First line, M integers, boys' lovely values from the 1st to the Mth. Second line, N integers, girls' lovely values from the 1st to the Nth.
Third part, S lines. Each line consists of two integers X and Y, means that the boy X and the girl Y have 8g.
One blank line between test cases.
Output
For each test case, your output should include three parts.
First part, one line, three integers X, A and B. X is the maximal total lovly value. A and B are the numbers of boys and girls invited.
Second part, one line, A integers, labels of the invited boys.
Third part, one line, B integers, labels of the invited girls.
If multiple solutions exist, output any of them.
Data Restriction
0 <= M, N <= 100; 0 <= S <= M*N.
1 <= lovely value <= 1024.
Sample Input
5 5 10 1 3 5 7 9 2 4 6 8 10 1 4 5 3 2 4 3 5 1 1 2 4 1 2 3 4 1 5 5 5
Sample Output
37 1 5 4 1 2 3 4 5
Author: CUI, Tianyi
Source: ZOJ Monthly, February 2009
求二分图的最大点权独立集, 等于总权值 - 最小点权覆盖集。最小点权覆盖集就是最小割。最小割的方案是在求过最大流的残留网络中,从s出发遍历所有的点,构成集合S。再根据S判断。
#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<set>
#include<cmath>
using namespace std;
const int maxn = 1e5 + 5;
const int INF = 1e9;
const double eps = 1e-6;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int, int> P;
#define fi first
#define se second
struct Edge {
int from, to, cap, flow;
};
struct Dinic {
int n, m, s, t;
vector<Edge> edges; // 边数的两倍
vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
bool vis[maxn]; // BFS使用
int d[maxn]; // 从起点到i的距离
int cur[maxn]; // 当前弧指针
void ClearAll(int n) {
for(int i = 0; i < n; i++) G[i].clear();
edges.clear();
}
void ClearFlow() {
for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
}
void AddEdge(int from, int to, int cap) {
//cout << from << ' ' << to << ' ' << cap << endl;
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));
queue<int> Q;
Q.push(s);
vis[s] = 1;
d[s] = 0;
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[x] + 1 == d[e.to] && (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 s, int t) {
this->s = s; this->t = t;
int flow = 0;
while(BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
vector<int> boy, girl;
void get_ans(int a, int b){
boy.clear();girl.clear();
int vis[maxn];
memset(vis, 0, sizeof vis);
queue<int> q;
q.push(0);
while(!q.empty()){
int pos = q.front();q.pop();
for(int i = 0;i < G[pos].size();i++){
Edge& e = edges[G[pos][i]];
if(e.cap > e.flow && !vis[e.to]){
vis[e.to] = 1;
q.push(e.to);
}
}
}
for(int i = 1;i <= a;i++){
if(vis[i]==1)
boy.push_back(i);
}
for(int i = a+1;i <= a+b;i++){
if(vis[i]==0)
girl.push_back(i-a);
}
}
};
Dinic g;
int main(){
int a, b, m;
while(scanf("%d%d%d", &a, &b, &m) != EOF){
g.ClearAll(a+b+5);
int source = 0, sink = a+b+1;
int total = 0;
for(int i = 1;i <= a;i++){
int x;
scanf("%d", &x);
total += x;
g.AddEdge(source, i, x);
}
for(int i = 1;i <= b;i++){
int x;
scanf("%d", &x);
total += x;
g.AddEdge(i+a, sink, x);
}
while(m--){
int x, y;
scanf("%d%d", &x, &y);
g.AddEdge(x, a+y, INF);
}
cout << total-g.Maxflow(source, sink);
g.get_ans(a, b);
cout << ' ' << g.boy.size() << ' ' << g.girl.size() << endl;
int bsize = g.boy.size();
for(int i = 0;i < bsize-1;i++){
cout << g.boy[i] << ' ';
}
if(bsize>=1)
cout << g.boy[bsize-1];
cout << endl;
int gsize = g.girl.size();
for(int i = 0;i < gsize-1;i++){
cout << g.girl[i] << ' ';
}
if(gsize>=1)
cout << g.girl[gsize-1];
cout << endl;
}
return 0;
}