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
时间: 2024-10-12 13:53:07