程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ2584 T-Shirt Gumbo 二分圖匹配(網絡流),poj2584gumbo

POJ2584 T-Shirt Gumbo 二分圖匹配(網絡流),poj2584gumbo

編輯:C++入門知識

POJ2584 T-Shirt Gumbo 二分圖匹配(網絡流),poj2584gumbo


1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int inf=0x3f3f3f3f; 6 const int sink=30; 7 8 struct Edge 9 { 10 int to; 11 int next; 12 int capacity; 13 14 void assign(int t,int n,int c) 15 { 16 to=t; next=n; capacity=c; 17 } 18 }; 19 20 Edge edgeList[2048]; 21 int head[40]; 22 int edgeCnt=0; 23 24 inline void init() 25 { 26 edgeCnt=0; 27 memset(head,-1,sizeof(head)); 28 } 29 30 char cmd[20]; 31 int X; 32 33 inline int idx(char s) 34 { 35 switch(s) 36 { 37 case 'S': return 1; 38 case 'M': return 2; 39 case 'L': return 3; 40 case 'X': return 4; 41 case 'T': return 5; 42 default : return -1; 43 } 44 } 45 46 inline void addEdge(int v1,int v2,int c) 47 { 48 edgeList[edgeCnt].assign(v2,head[v1],c); 49 head[v1]=edgeCnt++; 50 edgeList[edgeCnt].assign(v1,head[v2],0); 51 head[v2]=edgeCnt++; 52 } 53 54 bool input() 55 { 56 scanf("%s",cmd); 57 if(cmd[0]=='E') return false; 58 59 scanf("%d",&X); 60 for(int i=6;i<=X+5;i++) 61 { 62 scanf("%s",cmd); 63 int sm=idx(cmd[0]); 64 int lg=idx(cmd[1]); 65 for(int j=sm;j<=lg;j++) addEdge(j,i,inf); 66 addEdge(i,sink,1); 67 } 68 for(int i=1;i<=5;i++) 69 { 70 int n; scanf("%d",&n); 71 addEdge(0,i,n); 72 } 73 scanf("%s",cmd); 74 return true; 75 } 76 77 int dist[40]; 78 79 #include <queue> 80 81 int bfs() 82 { 83 memset(dist,0,sizeof(dist)); 84 dist[0]=1; 85 86 std::queue<int> __bfs; 87 __bfs.push(0); 88 89 while(!__bfs.empty()) 90 { 91 int cur=__bfs.front(); 92 __bfs.pop(); 93 94 for(int e=head[cur];e>-1;e=edgeList[e].next) 95 { 96 int __to=edgeList[e].to; 97 if(edgeList[e].capacity && !dist[__to]) 98 { 99 dist[__to]=dist[cur]+1; 100 __bfs.push(__to); 101 } 102 } 103 } 104 return dist[sink]; 105 } 106 107 int dinic_aux(int cur,int flow) 108 { 109 if(cur==sink) return flow; 110 111 int res=0; 112 int temp=0; 113 for(int e=head[cur];e>-1;e=edgeList[e].next) 114 { 115 int __to=edgeList[e].to; 116 if(dist[__to]==dist[cur]+1 && edgeList[e].capacity) 117 { 118 temp=dinic_aux(__to,std::min(flow,edgeList[e].capacity)); 119 res+=temp; 120 flow-=temp; 121 edgeList[e].capacity-=temp; 122 edgeList[e^1].capacity+=temp; 123 } 124 } 125 return res; 126 } 127 128 inline int dinic() 129 { 130 int res=0; 131 while(bfs()) res+=dinic_aux(0,inf); 132 return res; 133 } 134 135 const char success[]="T-shirts rock!"; 136 const char fail[]="I'd rather not wear a shirt anyway..."; 137 138 inline void solve() 139 { 140 bool proc=true; 141 while(proc) 142 { 143 init(); 144 proc=input(); 145 if(proc) printf("%s\n",dinic()==X?success:fail); 146 } 147 } 148 149 int main() { solve(); return 0; } Using Dinic Algorithm

這道題有兩種解決思路:

(1)拆點。將n件同樣尺碼的T恤拆成n個節點,然後對於每一個分離的節點向對應的人連邊

  效率比較低,點的個數最大有可能達到100以上

(2)網絡流。建模的基本思想與一般二分圖匹配的網絡流建模相同,只是從源點向T恤尺碼代表的節點連邊時,載量設為該種T恤的件數

  點的個數不超過30,相對比較高效

Appendix:二分圖匹配的網絡流建模:

約定二分圖的兩部分記作A和B

設立一個源點和匯點。源點同A中所有點連邊,載量設為1(表示該點只能在匹配中被選中一次);匯點同B中所有點連邊,載量也設為1

二分圖中原來的邊保留,令其方向為A→B,載量為任意正整數

對於網絡流問題,邊表是個很不錯的選擇。既能像鄰接表那樣節約空間,又能方便地記錄反向邊。

記正向邊的標號為2x,那麼反向邊的標號就是2x+1,訪問反向邊只需將正向邊的標號xor 1

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved