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

【网络流】太空飞行计划问题

2012-02-05 10:32 337 查看


这道题和前两天的最大获利是一模一样的,只是要输出方案,可以参见前两天的解题报告。

也可以看看兽哥http://user.qzone.qq.com/446801569?ptlang=2052,写得比较好

反正就是 获利=期望总收益-最小割。

输出方案的时候,纠结了很久。还是错了。正确的方法有两个。OJ说要从T向上遍历,最后输出的点都是必须遍历的。

证明:因为该点要选,必定是要盈利的点(假设不盈利,则会使总利润减少而不增加,不如不选),所以收益大于成本,所以割切在仪器那一边,所以要选的实验和仪器都在实验集合T集中,在sap过程中最后结束的标志是出现了断层(即割切),所以从T向上遍历,染过色的点,必然都属于T集。

实现方案一种即为遍历染色,另外一种是找到断层(vd[i]为零的),把所有在断层和T之间的点输出来。

#include <cstdio>

long t;
long s;
long n;
long m;

struct node
{
long i;
long f;
node* b;
node* next;
};

node* head[200];
long vd[200];
long d[200];
long size = 0;
long p[200];
long c[200];
bool used[200];
const long inf = 0x7fff0000;

inline long min(long a,long b)
{
if (a < b) return a;
return b;
}

long sap(long u,long flow)
{
if (u == t)
{
return flow;
}
long count = 0;
for (node* vv=head[u];vv;vv=vv->next)
{
long v = vv->i;
if (d[u]-d[v]==1)
{
long f = vv->f;
long tmp=sap(v,min(flow-count,f));
vv->f -= tmp;
vv->b->f += tmp;
count += tmp;
if (count == flow)
{
return count;
}
}
}
if (d[s] >= size)
{
return count;
}
vd[d[u]]--;
if (vd[d[u]] == 0)
{
d[s] = size;
}
d[u]++;
vd[d[u]]++;
return count;
}

void insert(long a,long b,long c,long d)
{
node* nn = new node;
nn->i = b;
nn->f = c;
nn->next = head[a];
head[a] = nn;

nn = new node;
nn->i = a;
nn->f = d;
nn->next = head[b];
head[b] = nn;

head[a]->b = head[b];
head[b]->b = head[a];
}

void dfs(long u)
{
used[u] = true;
if (u == s)
return;
for (node* vv=head[u];vv;vv=vv->next)
{
//        if (d[v]-d[u]==1&&!used[vv->i])
if (vv->b->f>0&&!used[vv->i])
{
dfs(vv->i);
}
}
}

int main()
{
freopen("shut.in","r",stdin);
freopen("shut.out","w",stdout);
scanf("%ld%ld",&n,&m);
size = n+m+2;
s = size;
t = size-1;
long amount = 0;
for (long i=1;i<n+1;i++)
{
scanf("%ld",p+i);
long b;char c;
while (1)
{
scanf("%ld%c",&b,&c);
insert(b+n,i,inf,0);
if (c == '\n') break;
}
insert(i,t,p[i],0);
amount += p[i];
}

for (long i=n+1;i<n+m+1;i++)
{
scanf("%ld",c+i);
insert(s,i,c[i],0);
}
long ans = 0;
vd[0] = size;
while (d[s] < size)
{
ans += sap(s,inf);
}
dfs(t);
for (long i=1;i<n+1;i++)
{
if (used[i])
printf("%ld ",i);
}
printf("\n");
for (long i=n+1;i<n+m+1;i++)
{
if (used[i])
printf("%ld ",i-n);
}
printf("\n%ld\n",amount-ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络 insert sap c