【题解】太空飞行计划问题
太空飞行计划问题
还是利用最小割的性质,这种题目叫做最大权闭合子图。
建模方法是这样
直接跑最小割,用奖金减去最小割就是答案。方案就是最后一遍bfs能遍历的点
考虑最小割的意义,就是把边删掉使得\(S,T\)不连通。
同样地,由于我们无法改变仪器和任务依赖的关系,只能改变一个点是否选择这个状态,所以我们让实验和仪器的连边为\(inf\)表示我们无法更改这个关系。
我们考虑鸽掉的奖金边是什么意思:这条奖金边是一次流的限制关系,是劣势的一方
考虑割掉的仪器边是什么意思:这条仪器边太小了,以至于实验赚的流随便流满了。
考虑总奖金减去最小割代价是什么,就是
\[\sum \text{奖金}-\sum \text{不要的奖金}-\sum \text{不买的仪器}
\]
实际上,我们可以考虑每一条流的流经路线,也能获得同样的理解。
其他题我能够独立完成,这道题不得不看题解...实在是我思维强度不够
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std; typedef long long ll;
int qaq,n;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57) f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
inline int sp(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57) f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
if(c=='\n') f=1;
return f?-ret:ret;
}
const int maxn=1e2+5;
struct E{
int to,nx,w;
E(){to=nx=w=0;}
E(const int&a,const int&b,const int&c){to=a;nx=b;w=c;}
}e[maxn<<4];
int head[maxn];
int cnt=1;
const int inf=0x3f3f3f3f;
int S,T,m;
inline void add(const int&fr,const int&to,const int&w,const int&f){
//printf("fr=%d to=%d w=%d cnt=%d\n",fr,to,w,cnt);
e[++cnt]=E(to,head[fr],w);
head[fr]=cnt;
if(f) add(to,fr,0,0);
}
int sum=0;
queue < int > q;
int d[maxn],cur[maxn];
inline bool bfs(){
for(register int t=1;t<=m+n+2;++t) d[t]=0,cur[t]=head[t];
d[S]=1;q.push(S);
while(q.size()){
register int now=q.front();
q.pop();
for(register int t=head[now];t;t=e[t].nx){
if(e[t].w>0&&d[e[t].to]==0){
d[e[t].to]=d[now]+1;
q.push(e[t].to);
}
}
}
return d[T];
}
int dfs(const int&now,int fl){
if(now==T||fl==0)return fl;
register int ret=0;
for(register int&t=cur[now];t;t=e[t].nx){
if(e[t].w>0&&d[e[t].to]==d[now]+1){
int d=dfs(e[t].to,min(e[t].w,fl));
e[t].w-=d;e[t^1].w+=d;ret+=d;fl-=d;
}
}
return ret;
}
inline int dinic(){
int ret=0;
while(bfs())ret+=dfs(S,inf);
return ret;
}
int main(){
#ifndef ONLINE_JUDGE
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
n=qr();m=qr();
S=1;T=n+m+2;
for(register int t=1;t<=n;++t){
int t1=qr();
add(S,t+1,t1,1);
sum+=t1;
while(1){
t1=sp();
//cout<<t<<' '<<t1<<endl;
add(t+1,abs(t1)+n+1,inf,1);
if(t1<0)break;
}
}
for(register int t=1;t<=m;++t) add(t+n+1,T,qr(),1);
int ans=sum-dinic();
for(register int t=head[S];t;t=e[t].nx)
if(d[e[t].to]) printf("%d ",e[t].to-1);
putchar('\n');
for(register int t=head[T];t;t=e[t].nx)
if(d[e[t].to]) printf("%d ",e[t].to-n-1);
printf("\n%d\n",ans);
return 0;
}
博客保留所有权利,谢绝学步园、码迷等不在文首明显处显著标明转载来源的任何个人或组织进行转载!其他文明转载授权且欢迎!