您的位置:首页 > 理论基础 > 计算机网络

线性规划与网络流24题 02太空飞行计划问题 最小割

2015-09-05 12:03 633 查看
线性规划与网络流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.



*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: