1. 程式人生 > >刷題總結——太空飛行計劃(最大權閉合子圖用最大流解決)

刷題總結——太空飛行計劃(最大權閉合子圖用最大流解決)

.com freopen static 出發 pre nbsp 資料 任務 代碼

題目:

題目描述

W 教授正在為國家航天中心計劃一系列的太空飛行。每次太空飛行可進行一系列商業性實驗而獲取利潤。現已確定了一個可供選擇的實驗集合 E={E1,E2,…,Em},和進行這些實驗需要使用的全部儀器的集合 I={I1, I2,…In}。 實驗 Ej 需要用到的儀器是 I 的子集 Rj∈I。配置儀器 Ik 的費用為 Ck 美元。實驗 Ej 的贊助商已同意為該實驗結果支付 Pj 美元。W 教授的任務是找出一個有效算法, 確定在一次太空飛行中要進行哪些實驗並因此而配置哪些儀器才能使太空飛行的凈收益最大。這裏凈收益是指進行實驗所獲得的全部收入與配置儀器的全部費用的差額。
對於給定的實驗和儀器配置情況,編程找出凈收益最大的試驗計劃,輸出最大收益值。

輸入格式

輸入文件第 1 行有 2 個正整數 m 和 n(1<=m,n<=400)。其中 m 是實驗數,n 是儀器數。接下來的 m 行,每行是一個實驗的有關數據(每個數不超過50)。第一個數贊助商同意支付該實驗的費用;接著是該實驗需要用到的若幹儀器的編號。最後一行的 n 個數是配置每個儀器的費用。

輸出格式

輸出一個整數,即最大的凈收益值。

樣例數據 1

輸入  [復制]

2 3
10 1 2
25 2 3
5 6 7

輸出

17

題解:

比較明顯可以看出是一個最大權閉合子圖(定義參見網上資料)

這裏給出求最大權閉合子圖方法:

建一個網絡,s連正點,邊權設為所連點點權;負點權向t點連邊,邊權為所出發點點權絕對值,點與點之間連原圖上的邊,邊權為inf

可以證明答案為正權和-最大流(最小割)(具體怎麽證的看http://www.cnblogs.com/wuyiqi/archive/2012/03/12/2391960.html(引用,%%%%%%))

代碼:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using
namespace std; const int inf=1e+9; const int N=1000; int first[N*2],go[N*N],next[N*N],rest[N*N],tot=1,lev[N]; int m,n,src,des,ans; char t; inline void comb(int a,int b,int c) { next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c; next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0; } inline bool bfs() { static int que[N*4],tail; for(int i=src;i<=des;i++) lev[i]=-1; que[tail=1]=src; lev[src]=0; for(int head=1;head<=tail;head++) { int u=que[head]; for(int e=first[u];e;e=next[e]) { int v=go[e]; if(rest[e]&&lev[v]==-1) { lev[v]=lev[u]+1; que[++tail]=v; if(v==des) return true; } } } return false; } inline int dinic(int u,int flow) { if(u==des) return flow; int res=0,delta,v; for(int e=first[u];e;e=next[e]) { v=go[e]; if(lev[v]>lev[u]&&rest[e]) { delta=dinic(v,min(rest[e],flow-res)); if(delta) { rest[e]-=delta; rest[e^1]+=delta; res+=delta; if(res==flow) break; } } } if(res!=flow) lev[u]=-1; return res; } void maxflow() { while(bfs()) ans+=dinic(src,inf); } int main() { //freopen("a.in","r",stdin); scanf("%d%d",&m,&n); src=0,des=n+m+1; int a,tot=0; for(int i=1;i<=m;i++) { scanf("%d",&a); comb(0,i,a); tot+=a; scanf("%c",&t); while(t!=\n) { scanf("%d",&a); comb(i,m+a,inf); scanf("%c",&t); } } for(int i=1;i<=n;i++) { scanf("%d",&a); comb(m+i,des,a); } maxflow(); cout<<tot-ans<<endl; return 0; }

刷題總結——太空飛行計劃(最大權閉合子圖用最大流解決)