1. 程式人生 > >LuoguP2762 太空飛行計劃問題(最大權閉合子圖,最小割)

LuoguP2762 太空飛行計劃問題(最大權閉合子圖,最小割)

題目描述

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

對於給定的實驗和儀器配置情況,程式設計找出淨收益最大的試驗計劃。

輸入輸出格式

輸入格式:

第1行有2 個正整數m和n。m是實驗數,n是儀器數。接下來的m 行,每行是一個實驗的有關資料。第一個數贊助商同意支付該實驗的費用;接著是該實驗需要用到的若干儀器的編號。最後一行的n個數是配置每個儀器的費用。

輸出格式:

第1 行是實驗編號;第2行是儀器編號;最後一行是淨收益。

解題思路:

相當於在實驗和儀器都是點,都有自己的點權,實驗為正,儀器為負。

實驗向儀器有一條有向邊。最後找到一個閉合子圖使原圖中不存在從這個子圖中指向圖外的邊。

正點權與源點連權值,負點權與匯點相連,求正點權-最小割就是答案。

程式碼:

  1 #include<queue>
  2
#include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 const int oo=0x3f3f3f3f; 7 struct pnt{ 8 int hd; 9 int lyr; 10 int now; 11 }p[10001]; 12 struct ent{ 13 int twd; 14 int lst; 15 int vls; 16
}e[1000000]; 17 int cnt; 18 int n,m; 19 int s,t; 20 int sum; 21 char tmp[100000]; 22 std::queue<int>Q; 23 void ade(int f,int t,int v) 24 { 25 cnt++; 26 e[cnt].twd=t; 27 e[cnt].vls=v; 28 e[cnt].lst=p[f].hd; 29 p[f].hd=cnt; 30 return ; 31 } 32 bool Bfs(void) 33 { 34 while(!Q.empty()) 35 Q.pop(); 36 for(int i=1;i<=t;i++) 37 p[i].lyr=0; 38 p[s].lyr=1; 39 Q.push(s); 40 while(!Q.empty()) 41 { 42 int x=Q.front(); 43 Q.pop(); 44 for(int i=p[x].hd;i;i=e[i].lst) 45 { 46 int to=e[i].twd; 47 if(p[to].lyr==0&&e[i].vls>0) 48 { 49 p[to].lyr=p[x].lyr+1; 50 if(to==t) 51 return true; 52 Q.push(to); 53 } 54 } 55 } 56 return false; 57 } 58 int Dfs(int x,int fll) 59 { 60 if(x==t) 61 return fll; 62 for(int& i=p[x].now;i;i=e[i].lst) 63 { 64 int to=e[i].twd; 65 if(p[to].lyr==p[x].lyr+1&&e[i].vls>0) 66 { 67 int ans=Dfs(to,std::min(fll,e[i].vls)); 68 if(ans>0) 69 { 70 e[i].vls-=ans; 71 e[((i-1)^1)+1].vls+=ans; 72 return ans; 73 } 74 } 75 } 76 return 0; 77 } 78 int Dinic(void) 79 { 80 int ans=0; 81 while(Bfs()) 82 { 83 int dlt; 84 for(int i=1;i<=t;i++) 85 p[i].now=p[i].hd; 86 while(dlt=Dfs(s,oo)) 87 ans+=dlt; 88 } 89 return ans; 90 } 91 int main() 92 { 93 // freopen("a.in","r",stdin); 94 scanf("%d%d",&m,&n); 95 s=n+m+1; 96 t=s+1; 97 for(int i=1;i<=m;i++) 98 { 99 int v; 100 scanf("%d",&v); 101 sum+=v; 102 ade(s,i,v); 103 ade(i,s,0); 104 int len=0; 105 memset(tmp,0,sizeof(tmp)); 106 std::cin.getline(tmp,10000); 107 while(sscanf(tmp+len,"%d",&v)==1) 108 { 109 ade(i,v+m,oo); 110 ade(v+m,i,0); 111 if(v==0)len++; 112 else{ 113 while(v) 114 { 115 len++; 116 v/=10; 117 } 118 } 119 len++; 120 } 121 } 122 for(int i=1;i<=n;i++) 123 { 124 int v; 125 scanf("%d",&v); 126 ade(i+m,t,v); 127 ade(t,i+m,0); 128 } 129 int ans=Dinic(); 130 for(int i=1;i<=m;i++) 131 { 132 if(p[i].lyr>1) 133 printf("%d ",i); 134 } 135 puts(""); 136 for(int i=1;i<=n;i++) 137 { 138 if(p[i+m].lyr>1) 139 printf("%d ",i); 140 } 141 puts(""); 142 printf("%d\n",sum-ans); 143 return 0; 144 }