PowerOJ 1737 网络流24题之二 太空飞行计划问题
原题地址:
https://www.oj.swust.edu.cn/problem/show/1737
题意:
W 教授正在为国家航天中心计划一系列的太空飞行。每次太空飞行可进行一系列商业
性实验而获取利润。现已确定了一个可供选择的实验集合E={E1,E2,…,Em},和进行这
些实验需要使用的全部仪器的集合I={I1,I2,…In}。实验Ej需要用到的仪器是I的子集Rj。
配置仪器Ik的费用为ck美元。实验Ej的赞助商已同意为该实验结果支付pj美元。W教授的
任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才
能使太空飞行的净收益最大。这里净收益是指进行实验所获得的全部收入与配置仪器的全部
费用的差额。
«编程任务:
对于给定的实验和仪器配置情况,编程找出净收益最大的试验计划。
数据范围
王晓东《线性规划和网络流24题》系列题目不需要管output.txt,是标准输入输出,多文件单数据。
所有题目中n的值一般小于150.
题解:
一篇最大权闭合子图博客
S向正边权点连边,权值为该点点权,负权点向T连边,权值为该点点权绝对值。正点向负点的边照连。
于是我们先把答案加上所有的正点点权和,然后跑最小割,答案减去最小割。
考虑其意义:
割掉一条S->u的边,表示不选这个实验,(减去其值)
割掉一条v->T的边,表示选择这个仪器,(减去其值)
一个实验,要么不选它,要么选择它(它的所有仪器)
于是是对应的。
输出方案就是残余图上与S联通的点(选择的),于是通过最后一次bfs的vis判断即可。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=10010;
const int inf=0x3f3f3f3f;
queue<int> Q;
int S,T,n,m,head[N],to[2*N],w[2*N],nxt[2*N],num=1,sum=0,dep[N];
bool vis[N];
void build(int u,int v,int ww)
{
num++;
to[num]=v; nxt[num]=head[u]; w[num]=ww; head[u]=num;
num++;
to[num]=u; nxt[num]=head[v]; w[num]=0; head[v]=num;
}
bool bfs()
{
while(!Q.empty()) Q.pop();
memset(vis,0,sizeof(vis));
Q.push(S); vis[S]=1; dep[S]=1;
while(!Q.empty())
{
int u=Q.front(); Q.pop();
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(vis[v]||w[i]<=0) continue;
dep[v]=dep[u]+1;
vis[v]=1; Q.push(v);
}
}
return vis[T];
}
int dfs(int u,int d)
{
if(u==T||d==0) return d;
int ret=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dep[v]!=dep[u]+1||w[i]<=0) continue;
int flow=dfs(v,min(d,w[i]));
d-=flow; ret+=flow;
w[i]-=flow; w[i^1]+=flow;
if(d==0) break;
}
if(ret==0) dep[u]=-1;
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
S=n+m+1; T=n+m+2;
for(int i=1;i<=n;i++)
{
int c; scanf("%d",&c);
build(S,i,c); sum+=c;
while(getchar()==' ')
{
int x;scanf("%d",&x);
build(i,n+x,inf);
}
}
for(int i=1;i<=m;i++)
{
int c;scanf("%d",&c);
build(n+i,T,c);
}
while(bfs()) sum-=dfs(S,inf);
for(int i=1;i<=n;i++) if(vis[i]) printf("%d ",i); puts("");
for(int i=n+1;i<=n+m;i++) if(vis[i]) printf("%d ",i-n); puts("");
printf("%d\n",sum);
return 0;
}

本文介绍了一道关于太空飞行计划的最大权闭合子图问题,并提供了详细的算法思路及C++实现代码。通过构建特殊的网络流图,利用最小割求解最大收益。
2731

被折叠的 条评论
为什么被折叠?



