1. 程式人生 > >洛谷P2762 太空飛行計劃問題(最小割)

洛谷P2762 太空飛行計劃問題(最小割)

get can char digi style edge bre utc name

傳送門

我們可以把實驗放在左邊,儀器放在右邊,點有點權,然後連對應的有向邊,就是求一個最大權閉合圖,可以轉化為最小割來做(關於這具體是個啥……可以百度胡伯濤《最小割模型在信息學競賽中的應用》)

總而言之,就是求一個圖,每一個點有點權,閉合圖就是若圖中有點$u$,且原圖中存在邊$(u,v)$,那麽點$v$也在圖中。然後求一個最大權的閉合圖即可(具體證明看上面)。最大權閉合圖可以轉化成下面那樣建圖之後求最小割

源點向所有實驗連邊,容量為收益,實驗向對應儀器連邊,容量為$inf$,儀器向匯點連邊,容量為花費,求一個最小割就好了,然後答案就是收益總和減去最小割

然後考慮怎麽求方案,因為最後一次bfs沒有增廣成功,而與源點想通的點就是閉合圖中的點,所以只要最後一次分層圖中$dep$不等於$-1$的點即可

 1 //minamoto
 2 #include<cstdio>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<queue>
 6 #define inf 0x3f3f3f3f
 7 using namespace std;
 8 inline bool read(int &res){
 9     res=0;char ch=getchar();
10     while(!isdigit(ch)){if(ch==\n) return false;ch=getchar();}
11 while(isdigit(ch)){res=res*10+ch-0,ch=getchar();} 12 return ch!=\n; 13 } 14 const int N=105,M=10005; 15 int ver[M],Next[M],head[N],edge[M],cur[N],tot=1; 16 int dep[N],n,m,s,t,ans; 17 queue<int> q; 18 inline void add(int u,int v,int e){ 19 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
20 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0; 21 } 22 bool bfs(){ 23 memset(dep,-1,sizeof(dep)); 24 for(int i=0;i<=n+m+1;++i) cur[i]=head[i]; 25 q.push(s),dep[s]=0; 26 while(!q.empty()){ 27 int u=q.front();q.pop(); 28 for(int i=head[u];i;i=Next[i]){ 29 int v=ver[i]; 30 if(dep[v]<0&&edge[i]) 31 dep[v]=dep[u]+1,q.push(v); 32 } 33 } 34 return ~dep[t]; 35 } 36 int dfs(int u,int limit){ 37 if(!limit||u==t) return limit; 38 int flow=0,f; 39 for(int i=cur[u];i;i=Next[i]){ 40 int v=ver[i];cur[u]=i; 41 if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){ 42 flow+=f,limit-=f; 43 edge[i]-=f,edge[i^1]+=f; 44 if(!limit) break; 45 } 46 } 47 return flow; 48 } 49 int dinic(){ 50 int flow=0; 51 while(bfs()) flow+=dfs(s,inf); 52 return flow; 53 } 54 int main(){ 55 scanf("%d%d",&m,&n); 56 s=0,t=n+m+1; 57 for(int i=1,x;i<=m;++i){ 58 scanf("%d",&x),ans+=x; 59 add(s,i,x); 60 while(read(x)) add(i,x+m,inf); 61 add(i,x+m,inf); 62 } 63 for(int i=m+1,x;i<=n+m;++i){ 64 scanf("%d",&x); 65 add(i,t,x); 66 } 67 ans-=dinic(); 68 for(int i=1;i<=m;++i) 69 if(~dep[i]) printf("%d ",i); 70 putchar(10); 71 for(int i=m+1;i<=n+m;++i) 72 if(~dep[i]) printf("%d ",i-m); 73 putchar(10); 74 printf("%d\n",ans); 75 return 0; 76 }

洛谷P2762 太空飛行計劃問題(最小割)