这两道题目都是多重二分匹配+枚举的做法,或者可以用网络流,实际上二分匹配也就实质是网络流,通过枚举区间,然后建立相应的图,判断该区间是否符合要求,并进一步缩小范围,直到求出解。不同之处在对是否满足条件的判断,可以求最大流或者最大匹配看匹配数目是否满足题意。
POJ 2289:
多重二分匹配:360ms
1 #include <iostream> 2 #include <cstdio> 3 #include <climits> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <algorithm> 10 #define esp 1e-6 11 #define pb push_back 12 #define in freopen("in.txt", "r", stdin); 13 #define out freopen("out.txt", "w", stdout); 14 #define print(a) printf("%d\n",(a)); 15 #define bug puts("********))))))"); 16 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 17 #define inf 0x0f0f0f0f 18 using namespace std; 19 typedef long long LL; 20 typedef vector<int> VI; 21 typedef vector<int>:: iterator IT; 22 #define N 1111 23 #define M 555 24 int n, m; 25 bool use[M]; 26 int link[M][N], cap[M]; 27 VI g[N]; 28 bool dfs(int x) 29 { 30 int t; 31 for(int i = 0; i < (int)g[x].size(); i++) 32 if(!use[t = g[x][i]]) 33 { 34 use[t] = true; 35 if(link[t][0] < cap[t]) 36 return link[t][++link[t][0]] = x, true; 37 else 38 { 39 for(int j = 1; j <= cap[t]; j++) 40 { 41 // use[t] = true; 42 if(dfs(link[t][j])) 43 return link[t][j] = x, true; 44 } 45 } 46 } 47 return false; 48 } 49 bool match(void) 50 { 51 memset(link, 0, sizeof(link)); 52 for(int i = 1; i <= n; i++) 53 { 54 memset(use, 0, sizeof(use)); 55 if(!dfs(i)) 56 return false; 57 } 58 return true; 59 } 60 void update(int mid) 61 { 62 for(int i = 1; i <= m; i++) 63 cap[i] = mid; 64 } 65 int main(void) 66 { 67 while(scanf("%d%d", &n, &m), n) 68 { 69 // for(int i = 1; i ) 70 char ch; 71 for(int i = 1; i <= n; i++) 72 { 73 g[i].clear(); 74 scanf("%*s%c", &ch); 75 while(ch != '\n') 76 { 77 int k; 78 scanf("%d%c", &k, &ch); 79 g[i].pb(k+1); 80 } 81 } 82 int l = 1, r = n, mid; 83 int ans = n; 84 while(l <= r) 85 { 86 mid = (l+r)>> 1; 87 update(mid); 88 if(match()) 89 { 90 ans = min(mid, ans); 91 r = mid-1; 92 } 93 else l = mid+1; 94 } 95 printf("%d\n", ans); 96 } 97 return 0; 98 }
网络流:589ms
1 #include <iostream> 2 #include <cstdio> 3 #include <climits> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <algorithm> 10 #define esp 1e-6 11 #define pb push_back 12 #define in freopen("in.txt", "r", stdin); 13 #define out freopen("out.txt", "w", stdout); 14 #define print(a) printf("%d\n",(a)); 15 #define bug puts("********))))))"); 16 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 17 #define inf 0x0f0f0f0f 18 using namespace std; 19 typedef long long LL; 20 typedef vector<int> VI; 21 typedef vector<int>:: iterator IT; 22 #define N 5000 23 #define M 600000 24 struct EDGE 25 { 26 int i, c; 27 EDGE *next, *ani; 28 } *Edge[N], E[M << 1], BE[M << 1], *tag[N]; 29 int Dfn[N], Now[N], cnt; 30 int n, m, src, sink, ndot; 31 32 void init(void) 33 { 34 cnt = 0; 35 memset(Edge, 0, sizeof(Edge)); 36 src = 0, sink = 1; 37 ndot = 2*n+2*m+2; 38 } 39 void add(int i, int j, int c, EDGE &e1, EDGE &e2) 40 { 41 e1.i = j, e1.c = c, e1.next = Edge[i], e1.ani = &e2, Edge[i] = &e1; 42 e2.i = i, e2.c = 0, e2.next = Edge[j], e2.ani = &e1, Edge[j] = &e2; 43 BE[cnt] = E[cnt], BE[cnt + 1] = E[cnt + 1]; 44 cnt += 2; 45 } 46 int ISAP(int s, int end, int flow) 47 { 48 if(s == end) 49 return flow; 50 int i, now = 0, vary, tab = ndot - 1; 51 for(EDGE *p = Edge[s]; p && flow; p = p->next) 52 if(p->c) 53 { 54 // bug 55 if(Dfn[s] == Dfn[i = p->i] + 1) 56 vary = ISAP(i, end, min(p->c, flow)), 57 p->c -= vary, p->ani->c += vary, now += vary, flow -= vary; 58 if(p->c) 59 tab = min(tab, Dfn[i]); 60 if(Dfn[src] == ndot) 61 return now; 62 } 63 if(now == 0) 64 { 65 if(--Now[Dfn[s]] == 0) 66 Dfn[src] = ndot; 67 Now[Dfn[s] = tab +1]++; 68 } 69 // print(now); 70 return now; 71 } 72 int max_flow(int s, int end) 73 { 74 memset(Dfn, 0, sizeof(Dfn)); 75 memset(Now, 0, sizeof(Now)); 76 Now[0] = ndot; 77 int ret = 0; 78 for(; Dfn[s] < ndot;) 79 { 80 ret += ISAP(s, end, inf); 81 } 82 return ret; 83 } 84 void Restore(void) 85 { 86 for(int i = 0; i < cnt; i++) 87 E[i] = BE[i]; 88 } 89 void update(int c) 90 { 91 Restore(); 92 for(int i = n+1; i <= n+m; i++) 93 { 94 tag[2*i]->c = c; 95 } 96 } 97 int main(void) 98 { 99 while(scanf("%d%d", &n, &m), n) 100 { 101 102 char ch; 103 init(); 104 for(int i = 1; i <= n; i++) 105 { 106 scanf("%*s%c", &ch); 107 while(ch != '\n') 108 { 109 int k; 110 scanf("%d%c", &k, &ch); 111 k += n+1; 112 add(2*i^1, 2*k, 1, E[cnt], E[cnt + 1]); 113 } 114 add(2*i, 2*i^1, 1, E[cnt], E[cnt + 1]); 115 add(src, 2*i, 1, E[cnt], E[cnt + 1]); 116 } 117 for(int i = 1; i <= m; i++) 118 { 119 add(2*(i+n), 2*(i+n)^1, inf, E[cnt], E[cnt + 1]); 120 tag[2*(i+n)] = &E[cnt]; 121 add(2*(i+n)^1, sink, inf, E[cnt], E[cnt + 1]); 122 } 123 int l = 1, r = n, mid; 124 int ans = n; 125 while(l <= r) 126 { 127 mid = (l+r)>> 1; 128 update(mid); 129 if(max_flow(src, sink) == n) 130 { 131 // bug 132 ans = min(mid, ans); 133 r = mid-1; 134 } 135 else l = mid+1; 136 } 137 printf("%d\n", ans); 138 } 139 return 0; 140 }
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
POJ 3189:
多重二分匹配:32ms
1 #include <iostream> 2 #include <cstdio> 3 #include <climits> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <algorithm> 10 #define esp 1e-6 11 #define pb push_back 12 #define in freopen("in.txt", "r", stdin); 13 #define out freopen("out.txt", "w", stdout); 14 #define print(a) printf("%d\n",(a)); 15 #define bug puts("********))))))"); 16 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 17 #define inf 0x3f3f3f3f 18 using namespace std; 19 typedef long long LL; 20 typedef vector<int> VI; 21 typedef vector<int>:: iterator IT; 22 #define N 30 23 #define M 1111 24 int n, m, mx, mi; 25 bool use[N]; 26 int link[N][M], cap[N], rank1[M][N]; 27 bool dfs(int x) 28 { 29 for(int i = 1; i <= m; i++) 30 if(rank1[x][i] >= mi && rank1[x][i] <= mx && !use[i]) 31 { 32 use[i] = true; 33 if(link[i][0] < cap[i]) 34 return link[i][++link[i][0]] = x, true; 35 else 36 for(int j = 1; j <= cap[i]; j++) 37 { 38 if(dfs(link[i][j])) 39 return link[i][j] = x, true; 40 } 41 } 42 return false; 43 } 44 bool match(void) 45 { 46 memset(link, 0, sizeof(link)); 47 for(int i = 1; i <= n; i++) 48 { 49 memset(use, 0, sizeof(use)); 50 if(!dfs(i)) 51 return false; 52 } 53 return true; 54 } 55 int main(void) 56 { 57 scanf("%d%d", &n, &m); 58 for(int i = 1; i <= n; i++) 59 for(int j = 1; j <= m; j++) 60 { 61 int x; 62 scanf("%d", &x); 63 rank1[i][x] = j; 64 } 65 for(int i = 1; i <= m; i++) 66 scanf("%d", cap + i); 67 int ans = m; 68 mx = mi = 1; 69 while(mi <= mx && mx <= m) 70 { 71 if(match()) 72 { 73 ans = min(mx-mi+1, ans); 74 mi++; 75 } 76 else mx++; 77 } 78 printf("%d\n", ans); 79 return 0; 80 }
网络流:110ms
1 #include <iostream> 2 #include <cstdio> 3 #include <climits> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cmath> 7 #include <vector> 8 #include <queue> 9 #include <algorithm> 10 #define esp 1e-6 11 #define pb push_back 12 #define in freopen("in.txt", "r", stdin); 13 #define out freopen("out.txt", "w", stdout); 14 #define print(a) printf("%d\n",(a)); 15 #define bug puts("********))))))"); 16 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++) 17 #define inf 0x3f3f3f3f 18 using namespace std; 19 typedef long long LL; 20 typedef vector<int> VI; 21 typedef vector<int>:: iterator IT; 22 #define N 3000 23 #define M 50000 24 25 struct EDGE 26 { 27 int i, c; 28 EDGE *next, *ani; 29 } *Edge[N], E[M << 1], BE[M << 1]; 30 int n, m, mx, mi, src, sink, cnt, ndot; 31 int cap[N], rank1[M][N], vis[N], dfn[N], Now[N]; 32 33 void add(int i, int j, int c, EDGE &e1, EDGE &e2) 34 { 35 e1.i = j, e1.c = c, e1.next = Edge[i], e1.ani = &e2, Edge[i] = &e1; 36 e2.i = i, e2.c = 0, e2.next = Edge[j], e2.ani = &e1, Edge[j] = &e2; 37 BE[cnt] = E[cnt], BE[cnt + 1] = E[cnt + 1]; 38 cnt += 2; 39 } 40 void init(void) 41 { 42 cnt = 0; 43 memset(Edge, 0, sizeof(Edge)); 44 src = 0, sink = 1; 45 ndot = 2*n+2*m+2; 46 } 47 void update(void) 48 { 49 for(int i = 0; i < cnt; i++) 50 E[i] = BE[i]; 51 for(int i = 1; i <= n; i++) 52 { 53 int u, v; 54 for(EDGE *p = Edge[2*i^1]; p; p = p->next) 55 { 56 u = i, v = p->i/2 - n; 57 if(rank1[u][v] >= mi && rank1[u][v] <= mx) 58 p->c = 1; 59 else p->c = 0; 60 } 61 } 62 } 63 void bfs(void) 64 { 65 queue<int> q; 66 q.push(sink); 67 vis[sink] = 1; 68 Now[0] = 1; 69 while(!q.empty()) 70 { 71 int u = q.front(); 72 int v; 73 q.pop(); 74 for(EDGE *p = Edge[u]; p; p = p->next) 75 if(!vis[v = p->i] && p->ani->c) 76 { 77 vis[v] = 1; 78 dfn[v] = dfn[u] + 1; 79 Now[dfn[v]]++; 80 q.push(v); 81 } 82 } 83 } 84 int ISAP(int s, int end, int flow) 85 { 86 if(s == end) 87 return flow; 88 int i, tab = ndot -1, now = 0, vary; 89 for(EDGE *p = Edge[s]; p && flow; p = p->next) 90 if(p->c) 91 { 92 if(dfn[s] == dfn[i = p->i] + 1) 93 vary = ISAP(i, end, min(flow, p->c)), 94 p->c -= vary, p->ani->c += vary, now +=vary, flow -= vary; 95 if(p->c) 96 tab = min(tab, dfn[i]); 97 if(dfn[src] == ndot) 98 return now; 99 } 100 if(now == 0) 101 { 102 if(--Now[dfn[s]] == 0) 103 dfn[src] = ndot; 104 ++Now[dfn[s] = tab + 1]; 105 } 106 return now; 107 } 108 int max_flow(int s, int end) 109 { 110 int ret = 0; 111 memset(Now, 0, sizeof(Now)); 112 memset(dfn, 0, sizeof(dfn)); 113 // bfs(); 114 Now[0] = ndot; 115 for(; dfn[s] < ndot;) 116 ret += ISAP(s, end, inf); 117 return ret; 118 } 119 int main(void) 120 { 121 122 scanf("%d%d", &n, &m); 123 init(); 124 for(int i = 1; i <= n; i++) 125 { 126 for(int j = 1; j <= m; j++) 127 { 128 int x; 129 scanf("%d", &x); 130 rank1[i][x] = j; 131 add(2*i^1, 2*(j+n), 1, E[cnt], E[cnt + 1]); 132 } 133 add(src, 2*i, inf, E[cnt], E[cnt + 1]); 134 add(2*i, 2*i^1, 1, E[cnt], E[cnt + 1]); 135 } 136 for(int i = 1; i <= m; i++) 137 { 138 scanf("%d", cap + i); 139 add(2*(i+n), 2*(i+n)^1, cap[i], E[cnt], E[cnt + 1]); 140 add(2*(i+n)^1, sink, inf, E[cnt], E[cnt + 1]); 141 } 142 int l = 1, r = m, mid; 143 // mx =m, mi = 1; 144 145 int ans = m; 146 while(l <= r) 147 { 148 mid = (l + r)>>1; 149 int flag = 0; 150 for(mi = 1, mx = mid; mx <= m; mx++, mi++) 151 { 152 update(); 153 if(max_flow(src, sink) == n) 154 { 155 int temp = mid; 156 ans = min(temp, ans); 157 flag = 1; 158 break; 159 } 160 } 161 if(flag) 162 r = mid-1; 163 else l = mid +1 ; 164 165 } 166 printf("%d\n", ans); 167 return 0; 168 }