【题解】太空飞行计划问题

太空飞行计划问题

还是利用最小割的性质,这种题目叫做最大权闭合子图。

建模方法是这样

img

直接跑最小割,用奖金减去最小割就是答案。方案就是最后一遍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;
}

posted @ 2019-07-23 21:35  谁是鸽王  阅读(229)  评论(0编辑  收藏  举报