太空飞行计划问题
还是利用最小割的性质,这种题目叫做最大权闭合子图。
建模方法是这样
直接跑最小割,用奖金减去最小割就是答案。方案就是最后一遍bfs能遍历的点
考虑最小割的意义,就是把边删掉使得(S,T)不连通。
同样地,由于我们无法改变仪器和任务依赖的关系,只能改变一个点是否选择这个状态,所以我们让实验和仪器的连边为(inf)表示我们无法更改这个关系。
我们考虑鸽掉的奖金边是什么意思:这条奖金边是一次流的限制关系,是劣势的一方
考虑割掉的仪器边是什么意思:这条仪器边太小了,以至于实验赚的流随便流满了。
考虑总奖金减去最小割代价是什么,就是
[sum ext{奖金}-sum ext{不要的奖金}-sum ext{不买的仪器}
]
实际上,我们可以考虑每一条流的流经路线,也能获得同样的理解。
其他题我能够独立完成,这道题不得不看题解...实在是我思维强度不够
//@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=='
') 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
",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('
');
for(register int t=head[T];t;t=e[t].nx)
if(d[e[t].to]) printf("%d ",e[t].to-n-1);
printf("
%d
",ans);
return 0;
}