码迷,mamicode.com
首页 > 其他好文 > 详细

POJ2584 T-Shirt Gumbo 二分图匹配(网络流)

时间:2016-04-16 23:12:58      阅读:436      评论:0      收藏:0      [点我收藏+]

标签:

技术分享
  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

POJ2584 T-Shirt Gumbo 二分图匹配(网络流)

标签:

原文地址:http://www.cnblogs.com/Onlynagesha/p/5399579.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!