线性规划与网络流24题 02太空飞行计划问题
题意:
给一个图,一些点带正权值,一些点带负权值。选一个正权值点必须要选一些指定的负权值点,问怎样选点获得最大权值。
思路:
最小割是有多解的,所以只要最大流对了就不管了。。。
这是一个求最大闭合子图的问题。
定理:从源点S向所有正权值点引边,容量为权值;从所有负权点像T引边,容量为权值的绝对值。正权值和负权值点之间有关系则引边,容量为无穷大。跑一遍最大流,ans = (正权值和) - MAX_flow。子图为s-t割中s部分。
割点集具体实现方法就是跑完最大流后s仍然能够到达的点,割点集不唯一。
源码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define inf (1000000000)
const int MAXN = 1000 + 5;
int head[MAXN], cnt;
char str[10000];
int TOT;
struct Edge
{
int u, v;
int ne, flow;
Edge(){}
Edge(int _u, int _v, int _flow)
{
u = _u, v = _v, flow = _flow;
ne = head[u];
}
}edge[MAXN * MAXN * 2];
void add_edge(int u, int v, int flow)
{
edge[cnt] = Edge(u, v, flow);
head[u] = cnt++;
edge[cnt] = Edge(v, u, 0);
head[v] = cnt++;
}
int n, m;
void init()
{
TOT = 0;
cnt = 0;
memset(head, -1, sizeof(head));
getchar();
for(int i = 1 ; i <= n ; i++){
gets(str);
int f = 1;
int temp = 0;
int j = 0;
// printf("i = %d\n", i);
while(str[j] == ' ') j++;
for(; str[j] != '\0' ; j++){
// printf("str[%d] = %c, temp = %d\n", j, str[j], temp);
if(str[j] >= '0' && str[j] <= '9'){
// printf("second\n");
temp = temp * 10 + str[j] - '0';
}
else{
if(f){
// printf("%d temp = %d\n", f, temp);
TOT += temp;
add_edge(0, i, temp);
temp = 0; f = 0;
}
else{
// printf("%d temp = %d\n", f, temp);
add_edge(i, temp + n, inf);
temp = 0;
}
}
}
if(f){
TOT += temp;
add_edge(0, i, temp);
temp = 0; f = 0;
// printf("%d temp = %d\n", f, temp);
}
else{
add_edge(i, temp + n, inf);
temp = 0;
// printf("%d temp = %d\n", f, temp);
}
// printf("\n");
}
int temp = 0;
for(int i = n + 1 ; i <= n + m ; i++){
scanf("%d", &temp);
add_edge(i, n + m + 1, temp);
}
}
int d[MAXN], vis[MAXN], cur[MAXN];
queue<int>que;
void BFS(int t, int flag)
{
memset(vis, 0, sizeof(vis));
memset(d, -1, sizeof(d));
while(!que.empty()) que.pop();
d[t] = 0;
vis[t] = 1;
que.push(t);
while(!que.empty()){
int u = que.front(); que.pop();
for(int now = head[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(vis[v] == 0){
if(!flag || (flag && edge[now].flow)){
d[v] = d[u] + 1;
vis[v] = 1;
que.push(v);
}
if(flag && v == t)
return;
}
}
}
}
int p[MAXN], num[MAXN];
int Augment(int s, int t)
{
int flow = inf;
int now = t;
while(now != s){
flow = min(flow, edge[p[now]].flow);
now = edge[p[now]].u;
}
now = t;
while(now != s){
edge[p[now]].flow -= flow;
edge[p[now] ^ 1].flow += flow;
now = edge[p[now]].u;
}
return flow;
}
int ISAP(int s, int t)
{
int flow = 0;
BFS(t, 0);
memset(num, 0, sizeof(num));
for(int i = 0 ; i <= n + m + 1 ; i++)
cur[i] = head[i], num[d[i]]++;
int u = s;
while(d[s] < n + m + 3){
if(u == t){
flow += Augment(s, t);
u = s;
}
int ok = 0;
for(int now = cur[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(edge[now].flow > 0 && d[v] == d[u] - 1){
cur[u] = now;
p[v] = now;
u = v;
ok = 1;
break;
}
}
if(!ok){
int tm = n + m + 2;
for(int now = head[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(edge[now].flow) tm = min(tm, d[v]);
}
if(--num[d[u]] == 0) break;
num[d[u] = tm + 1]++;
cur[u] = head[u];
if(u != s) u = edge[p[u]].u;
}
}
return flow;
}
int in[MAXN];
void min_craft()
{
memset(in, 0, sizeof(in));
in[0] = 1;
while(!que.empty()) que.pop();
que.push(0);
while(!que.empty()){
int u = que.front(); que.pop();
for(int now = head[u] ; now != -1 ; now = edge[now].ne){
int v = edge[now].v;
if(edge[now].flow > 0 && !in[v]){
in[v] = 1;
que.push(v);
}
}
}
}
int main()
{
freopen("shut10.in", "r", stdin);
while(scanf("%d%d", &n, &m) != EOF){
init();
int ans = TOT - ISAP(0, n + m + 1);
BFS(0, 1);
min_craft();
int f = 1;
for(int i = 1 ; i <= n ; i++){
if(in[i]){
if(f) f = 0;
else printf(" ");
printf("%d", i);
}
}
printf("\n");
f = 1;
for(int i = n + 1 ; i <= n + m ; i++){
if(in[i]){
if(f) f = 0;
else printf(" ");
printf("%d", i - n);
}
}
printf("\n");
printf("%d\n", ans);
}
return 0;
}
/*
1 7 9 24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31
11
Process returned 0 (0x0) execution time : 0.575 s
Press any key to continue.
*/