zoukankan      html  css  js  c++  java
  • 二分图题目泛做(为了对应陈学姐的课件)

    题1:BZOJ1854 SCOI2010游戏 (最大匹配,如果不能匹配就break)

    每个属性x,y分别向i连条边,匹配属性到不能匹配为止。注意是属性找武器,所以要循环属性。

    输出即可。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 const int N = 1000000 + 5;
    10 
    11 int tim = 0, n, tot = 0;
    12 int first[N], next[N<<1];
    13 int u[N<<1], v[N<<1];
    14 int used[N], girl[N];
    15 
    16 void Add(int s, int t){
    17   ++ tot;
    18   u[tot] = s; v[tot] = t;
    19   next[tot] = first[u[tot]];
    20   first[u[tot]] = tot;
    21 }
    22 
    23 bool find(int now){
    24   for(int i = first[now]; i; i = next[i]){
    25     if(used[v[i]] != tim){
    26       used[v[i]] = tim;
    27 
    28       if(girl[v[i]] == 0 || find(girl[v[i]])){
    29         girl[v[i]] = now;
    30         return true;
    31       }
    32     }
    33   }
    34 
    35   return false;
    36 }
    37 
    38 #define ONLINE_JUDGE
    39 int main(){
    40 #ifndef ONLINE_JUDGE
    41   freopen("game.in", "r", stdin);
    42   freopen("game.out", "w", stdout);
    43 #endif
    44   
    45   int x, y;
    46   
    47   scanf("%d", &n);
    48   for(int i = 1; i <= n; ++ i){
    49     scanf("%d%d", &x, &y);
    50     Add(x, i); Add(y, i);
    51   }
    52 
    53   int ans = 0;
    54   for(int i = 1; i <= 10000; ++ i){
    55     ++ tim;
    56     if(find(i))
    57       ++ ans;
    58     else break;
    59   }
    60 
    61   printf("%d
    ", ans);
    62 
    63 #ifndef ONLINE_JUDGE
    64   fclose(stdin); fclose(stdout);
    65 #endif
    66   return 0;
    67 }
    BZOJ 1854

     题2:HDU2768 Cat V.S. Dog

    交了10遍。后来才发现错的地方是因为保存的地方,我是直接return (int)x + (int)ss[0], 但是这样的话,我们要注意C2和D1就是等价的了。。。。做的时候要考虑,我们是把有冲突的人之间连边,不要老考虑狗和猫的关系。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int N = 500 + 5;
     6 const int M = 500 * 500 + 5;
     7 
     8 int tim = 0, tot = 0;
     9 int x = 0, a;
    10 int n, m, k;
    11 char ss[10];
    12 int first[N], nxt[M];
    13 int u[M], v[M];
    14 int usd[N], girl[N];
    15 
    16 struct data{
    17   string s1, s2;
    18 }p[N];
    19 
    20 void Add(int s, int t){
    21   ++ tot;
    22   u[tot] = s; v[tot] = t;
    23   nxt[tot] = first[u[tot]];
    24   first[u[tot]] = tot;
    25 }
    26 
    27 bool find(int x){
    28   for(int i = first[x]; i; i = nxt[i]){
    29     if(usd[v[i]] != tim){
    30       usd[v[i]] = tim;
    31       if(!girl[v[i]] || find(girl[v[i]])){
    32         girl[v[i]] = x;
    33         return true;
    34       }
    35     }
    36   }
    37 
    38   return false;
    39 }
    40 
    41 void Solve(){
    42   memset(first, 0, sizeof first);
    43   memset(girl, 0, sizeof girl);
    44   tot = 0;
    45   
    46   cin >> n >> m >> k;
    47   for(int i = 1; i <= k; ++ i){
    48     cin >> p[i].s1 >> p[i].s2;
    49   }
    50   for(int i = 1; i <= k; ++ i){
    51     for(int j = 1; j <= k; ++ j){
    52       if(i != j){
    53         if(p[i].s1 == p[j].s2 || p[j].s1 == p[i].s2){
    54           Add(i, j); Add(j, i);
    55         }
    56       }
    57     }
    58   }
    59 
    60   int ans = 0;
    61   
    62   for(int i = 1; i <= k; ++ i){
    63     ++ tim;
    64     if(find(i))
    65       ++ ans;
    66   }
    67 
    68   printf("%d
    ", k - ans/2);
    69 }
    70 
    71 int main(){
    72   ios::sync_with_stdio(false);
    73   
    74   int t;
    75 
    76   cin >> t;
    77   
    78   while(t --){
    79     Solve();
    80   }
    81 
    82   return 0;
    83 }
    HDU 2768

     题3: POJ 1325 Machine Schedule

    求二分图的最小覆盖:寻找一个最小的点集,使得图中每一条边至少有一个点在该点集中。

    二分图的最小覆盖 = 最大匹配。注意所有机器开始都在0模式,所以一开始与0相连的边不要加入二分图。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 const int N = 1000 + 5;
     9 
    10 int n, m, k;
    11 int first[N], next[N<<1];
    12 int u[N<<1], v[N<<1];
    13 int usd[N], g[N], tim = 0, tot = 0;
    14 
    15 void Add(int s, int t){
    16   ++ tot;
    17   u[tot] = s; v[tot] = t;
    18   next[tot] = first[u[tot]];
    19   first[u[tot]] = tot;
    20 }
    21 
    22 bool find(int x){
    23   for(int i = first[x]; i; i = next[i]){
    24     if(usd[v[i]] != tim){
    25       usd[v[i]] = tim;
    26       if(!g[v[i]] || find(g[v[i]])){
    27         g[v[i]] = x;
    28         return true;
    29       }
    30     }
    31   }
    32 
    33   return false;
    34 }
    35 
    36 
    37 int main(){
    38   int x, y, z;
    39   
    40   while(scanf("%d", &n)){
    41     if(n == 0) break;
    42     scanf("%d%d", &m, &k);
    43     tot = 0;
    44     memset(first, 0, sizeof first);
    45     memset(g, 0, sizeof g);
    46     
    47     for(int i = 1; i <= k; ++ i){
    48       scanf("%d%d%d", &x, &y, &z);
    49 
    50       if(y && z) Add(y, z);
    51     }
    52 
    53     int ans = 0;
    54     
    55     for(int i = 1; i < n; ++ i){
    56       ++ tim;
    57       if(find(i)) ++ ans;
    58     }
    59 
    60     printf("%d
    ", ans);
    61   }
    62 
    63   return 0;
    64 }
    POJ 1325

    题4: POJ 2226 Muddy Fields (感觉这题比较好)

    给一个N*M的矩形,*代表泥地,“.”代表草地,求最少用多少块木板可以覆盖泥地。注:不能覆盖草地。

    先来考虑可以覆盖草地的情况,那么就是找到每一个*,假设其坐标为i行j列,那么就i->j连边。跑最大匹配。

    如果不可以,就把在同一行上的连通的看做一行,同一列上的连通的看做一列。像上面一样连边。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <iostream>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 const int N = 50 + 5;
    10 const int NS = 10000 + 5;
    11 
    12 int r, c;
    13 int cnth = 0, cntl = 0;
    14 int h[N][N], l[N][N];
    15 int lk[N*N][N*N];
    16 char str[N][N];
    17 int tot = 0, tim = 0, ans = 0;
    18 int first[NS], next[NS<<1];
    19 int v[NS<<1];
    20 int usd[NS], g[NS];
    21 
    22 void Add(int s, int t){
    23   ++ tot;
    24   v[tot] = t;
    25   next[tot] = first[s];
    26   first[s] = tot;
    27 }
    28 
    29 bool find(int x){
    30   for(int i = first[x]; i; i = next[i]){
    31     if(usd[v[i]] != tim){
    32       usd[v[i]] = tim;
    33       if(!g[v[i]] || find(g[v[i]])){
    34         g[v[i]] = x;
    35         return true;
    36       }
    37     }
    38   }
    39   return false;
    40 }
    41 
    42 int main(){
    43   while(scanf("%d%d", &r, &c) != EOF){
    44     for(int i = 1; i <= r; ++ i){
    45       scanf("%s", str[i] + 1);
    46     }
    47 
    48     for(int i = 1; i <= r; ++ i){
    49       for(int j = 1; j <= c; ++ j){
    50         if(str[i][j] == '.') continue;
    51         if(h[i][j]) continue;
    52         else h[i][j] = ++ cnth;
    53         for(int k = j + 1; k <= c; ++ k)
    54           if(str[i][k] == '*') h[i][k] = cnth;
    55           else break;
    56       }
    57     }
    58     for(int j = 1; j <= c; ++ j){
    59       for(int i = 1; i <= r; ++ i){
    60         if(str[i][j] == '.') continue;
    61         if(l[i][j]) continue;
    62         else l[i][j] = ++ cntl;
    63         for(int k = i + 1; i <= r; ++ k)
    64           if(str[k][j] == '*') l[k][j] = cntl;
    65           else break;
    66       }
    67     }
    68 
    69     int x, y;
    70     
    71     for(int i = 1; i <= r; ++ i){
    72       for(int j = 1; j <= c; ++ j){
    73         if(lk[x = h[i][j]][y = l[i][j]]) continue;
    74         lk[x][y] ++;
    75         Add(x, y);
    76       }
    77     }
    78     
    79     for(int i = 1; i <= cnth; ++ i){
    80       ++ tim;
    81       if(find(i)) ++ ans;
    82     }
    83 
    84     printf("%d
    ", ans);
    85   }
    86 
    87   return 0;
    88 }
    POJ 2226

    题5: COJS 骑士共存

    求二分图的最大独立集:求一个最大的点集,使任意两点间无直接连边。

    二分图的最大独立集 = 点数 - 最大匹配。

    把棋盘染色,跑图的时候只跑一半的点。注意常数!注意常数!注意常数!重要的事情说三遍。

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int N = 200 + 5;
     6 const int M = 320000 + 5;
     7 
     8 int n, m;
     9 int tot = 0, tim = 0, ans = 0;
    10 int first[N * N], next[M<<1];
    11 int u[M<<1], v[M<<1];
    12 int girl[N * N], usd[N * N];
    13 bool b[N * N];
    14 int dx[8] = {-2, -1, 1, 2, -2, -1, 1, 2}, dy[8] = {-1, -2, -2, -1, 1, 2, 2, 1};                  
    15 
    16 void Add(int s, int t){
    17   ++ tot;
    18   u[tot] = s; v[tot] = t;
    19   next[tot] = first[s];
    20   first[s] = tot;
    21 }
    22 
    23 bool find(int x){
    24   for(int i = first[x]; i; i = next[i]){
    25     if(usd[v[i]] != tim){
    26       usd[v[i]] = tim;
    27       if(!girl[v[i]] || find(girl[v[i]])){
    28         girl[v[i]] = x;
    29         return true;
    30       }
    31     }
    32   }
    33   return false;
    34 }
    35 
    36 int c(int i, int j){
    37   return j + (i - 1) * n;
    38 }
    39 
    40 int main(){
    41 #ifndef ONLINE_JUDGE
    42   freopen("knight.in", "r", stdin);
    43   freopen("knight.out", "w", stdout);
    44 #endif
    45   
    46   int x, y;
    47   
    48   scanf("%d%d", &n, &m);
    49   for(int i = 1; i <= m; ++ i){
    50     scanf("%d%d", &x, &y);
    51     b[c(x, y)] = true;
    52   }
    53 
    54   int s, t;
    55   
    56   for(int i = 1; i <= n; ++ i){
    57     for(int j = (i & 1) + 1; j <= n; j += 2){
    58       if(!b[s = c(i, j)])
    59         for(int k = 0; k < 8; ++ k){
    60           if(i + dx[k] < 1 || i + dx[k] > n || j + dy[k] < 1 || j + dy[k] > n) continue;
    61           if(b[t = c(i + dx[k], j + dy[k])]) continue;
    62           Add(s, t); Add(t, s);
    63         }
    64     }
    65   }
    66 
    67   for(int i = 1; i <= n; ++ i){
    68     for(int j = 1; j <= n; ++ j){
    69       if(i + j & 1 && !b[s = c(i, j)]){
    70         ++ tim;
    71         if(find(s)) ++ ans;
    72       }
    73     }
    74   }
    75 
    76   printf("%d
    ", n * n - m - ans);
    77 
    78 #ifndef ONLINE_JUDGE
    79   fclose(stdin); fclose(stdout);
    80 #endif
    81   return 0;
    82 }
    COJS 骑士共存

    题6: POJ 1422 Air Raid

    求二分图的最小路径覆盖,用尽量少的不相交的路径覆盖有向无环图的所有点。

    原图的路径覆盖和新图的匹配间有对应关系: 每条覆盖边都是匹配中的一条边,且只有路径的最后一个点没有被匹配上 路径要求不能相交,恰好对应匹配中两匹配边不能有公共端点 于是求最大匹配后,不能被匹配上的点,即是路径的最后一个点。有多少个不能被匹配上的点,就有多少条路径存在 路径数=原点数-匹配边数。因此是匹配边数最大,即是使路径数最小

    这题是裸题。拆点后直接做。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 const int N = 1000 + 5;
     9 
    10 int n, m, k;
    11 int first[N], next[N<<1];
    12 int u[N<<1], v[N<<1];
    13 int usd[N], g[N], tim = 0, tot = 0;
    14 
    15 void Add(int s, int t){
    16   ++ tot;
    17   u[tot] = s; v[tot] = t;
    18   next[tot] = first[u[tot]];
    19   first[u[tot]] = tot;
    20 }
    21 
    22 bool find(int x){
    23   for(int i = first[x]; i; i = next[i]){
    24     if(usd[v[i]] != tim){
    25       usd[v[i]] = tim;
    26       if(!g[v[i]] || find(g[v[i]])){
    27         g[v[i]] = x;
    28         return true;
    29       }
    30     }
    31   }
    32 
    33   return false;
    34 }
    35 
    36 
    37 int main(){
    38   int t, x, y;
    39 
    40   scanf("%d", &t);
    41 
    42   while(t --){
    43     memset(first, 0, sizeof first);
    44     memset(g, 0, sizeof g);
    45     tot = 0;
    46     
    47     scanf("%d%d", &n, &m);
    48     for(int i = 1; i <= m; ++ i){
    49       scanf("%d%d", &x, &y);
    50       Add(x, y + n);
    51     }
    52 
    53     int ans = 0;
    54     
    55     for(int i = 1; i <= n * 2; ++ i){
    56       ++ tim;
    57       if(find(i)) ++ ans;
    58     }
    59 
    60     printf("%d
    ", n - ans);
    61   }
    62 
    63   return 0;
    64 }
    POJ 1422

    题7: COJS 魔术球问题(感觉挺好的一个题)

    求二分图的最小路径覆盖。

    二分把这个题转化成了判定问题。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int N = 60 + 5;
      6 const int M = 320000 + 5;
      7 
      8 int n, tim = 0, tot = 0, ans;
      9 int first[M<<1], next[M<<1], v[M<<1];
     10 int g[M<<1], usd[M<<1];
     11 
     12 void Add(int from, int to){
     13   ++ tot;
     14   v[tot] = to;
     15   next[tot] = first[from];
     16   first[from] = tot;
     17 }
     18 
     19 bool judge(int i, int j){
     20   int tp1, tp2;
     21 
     22   tp1 = i + j; tp2 = sqrt(tp1);
     23   if(tp2 * tp2 == tp1) return true;
     24   return false;
     25 }
     26 void build(int nv){
     27   tot = 0;
     28   memset(first, 0, sizeof first);
     29   memset(g, 0, sizeof g);
     30   
     31   for(int i = 1; i <= nv; ++ i){
     32     for(int j = i + 1; j <= nv; ++ j){
     33       if(judge(i, j)){
     34         Add(i, j);
     35       }
     36     }
     37   }
     38 }
     39 
     40 bool find(int x){
     41   for(int i = first[x]; i; i = next[i]){
     42     if(usd[v[i]] != tim){
     43       usd[v[i]] = tim;
     44 
     45       if(!g[v[i]] || find(g[v[i]])){
     46         g[v[i]] = x;
     47         return true;
     48       }
     49     }
     50   }
     51 
     52   return false;
     53 }
     54 
     55 bool check(int nv){
     56   int kk = 0;
     57   
     58   for(int i = 1; i <= nv; ++ i){
     59     ++ tim;
     60     if(find(i)) ++ kk;
     61   }
     62 
     63   return (nv - kk) <= n;
     64 }
     65 
     66 void Input(){
     67   scanf("%d", &n);
     68 }
     69 
     70 void Solve(){
     71   int l = 1, r = 1600;
     72   int mid;
     73 
     74   while(l <= r){
     75     mid = l + (r - l) / 2;
     76     build(mid);
     77     if(check(mid)){
     78       l = mid + 1;
     79       ans = mid;
     80     }
     81     else r = mid - 1;
     82   }
     83 }
     84 
     85 void Output(){
     86   printf("%d
    ", ans);
     87 }
     88 
     89 int main(){
     90 #ifndef ONLINE_JUDGE
     91   freopen("balla.in", "r", stdin);
     92   freopen("balla.out", "w", stdout);
     93 #endif
     94 
     95   Input();
     96   Solve();
     97   Output();
     98 
     99 #ifndef ONLINE_JUDGE
    100   fclose(stdin); fclose(stdout);
    101 #endif
    102 
    103   return 0;
    104 }
    COJS 魔术球

     题8: BZOJ 3008 象棋

    题目大意:一个棋盘,分别给出K个棋子指定的起始位置和终止位置,求把所有棋子都移动到终止位置的最小步数。注意,同一时刻一个格子里面只能有一个棋子。

    求最佳完美匹配。先处理出所有棋子到每一个终止位置的最小步数,以最小步数为边权连边,直接跑KM算法就可以。

    因为所有棋子都是相同的,那么在将要在同一个格子里面出现的时候,相当于被另一个棋子替掉了。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 #include <iostream>
      6  
      7 using namespace std;
      8  
      9 const int N = 1000 + 5;
     10 const int oo = 0x3f3f3f3f;
     11  
     12 int n, m, k, a, b;
     13 int cnt = 0;
     14 char mp[N][N];
     15 bool vi[N][N];
     16 int dx[10], dy[10];
     17 int w[N][N], head[N], stx[N], sty[N], edx[N], edy[N];
     18 int dst[N][N];
     19  
     20 struct Edge {
     21   int to, next;
     22 }edges[500000 + 5];
     23  
     24 struct QUEUE {
     25   int x, y;
     26 }que[N * 20];
     27  
     28 struct KM {
     29   int tim;
     30   int lx[N], ly[N], sx[N], by[N], st[N], g[N];
     31  
     32   KM() {
     33     tim = 0;
     34     memset(sx, 0, sizeof sx);
     35     memset(by, 0, sizeof by);
     36   }
     37   void Clear() {
     38     memset(g, 0, sizeof g);
     39     memset(lx, 0x80, sizeof lx);
     40     memset(ly, 0, sizeof ly);
     41   }
     42  
     43   bool find(int u) {
     44     sx[u] = tim;
     45     for(int i = head[u]; i; i = edges[i].next) {
     46       int v = edges[i].to;
     47  
     48       if(by[v] == tim) continue;
     49  
     50       int t = lx[u] + ly[v] - w[u][v];
     51  
     52       if(!t) {
     53         by[v] = tim;
     54         if(!g[v] || find(g[v])) {
     55           g[v] = u;
     56           return true;
     57         }
     58       }
     59       else{
     60         st[v] = min(st[v], t);
     61       }
     62     }
     63     return false;
     64   }
     65  
     66   int km() {
     67     Clear();
     68     for(int i = 1; i <= k; ++ i) {
     69       for(int j = 1; j <= k; ++ j) {
     70         lx[i] = max(w[i][j], lx[i]);
     71       }
     72     }
     73     for(int i = 1; i <= k; ++ i) {
     74       memset(st, 0x3f, sizeof st);
     75       for(;;) {
     76         ++ tim;
     77         if(find(i)) break;
     78  
     79         int d = oo;
     80  
     81         for(int j = 1; j <= k; ++ j)
     82           if(by[j] != tim)
     83             d = min(st[j], d);
     84         for(int j = 1; j <= k; ++ j) {
     85           if(sx[j] == tim) lx[j] -= d;
     86           if(by[j] == tim) ly[j] += d;
     87           else st[j] -= d;
     88         }
     89       }
     90     }
     91      
     92     int res = 0;
     93  
     94     for(int i = 1; i <= k; ++ i)
     95       res += w[g[i]][i];
     96  
     97     return res;
     98   }
     99 }bsyx;
    100  
    101 void Input() {
    102   scanf("%d%d%d%d%d", &n, &m, &k, &a, &b);
    103   for(int i = 1; i <= n; ++ i) {
    104     scanf("%s", mp[i] + 1);
    105   }
    106   for(int i = 1; i <= k; ++ i) {
    107     scanf("%d%d", &stx[i], &sty[i]);
    108   }
    109   for(int i = 1; i <= k; ++ i) {
    110     scanf("%d%d", &edx[i], &edy[i]);
    111   }
    112 }
    113  
    114 void bfs(int st_x, int st_y) {
    115   int head, tail;
    116  
    117   memset(vi, false, sizeof vi);
    118   head = tail = 1;
    119   que[head].x = st_x; que[head].y = st_y;
    120   dst[st_x][st_y] = 0;
    121   vi[st_x][st_y] = true;
    122    
    123   while(head <= tail) {
    124     int x = que[head].x, y = que[head].y;
    125  
    126     for(int i = 1; i <= 8; ++ i) {
    127       int nx = dx[i] + x;
    128       int ny = dy[i] + y;
    129  
    130       if(nx < 1 || ny < 1 || nx > n || ny > m) continue;
    131       if(mp[nx][ny] == '*') continue;
    132       if(vi[nx][ny]) continue;
    133       ++ tail;
    134       que[tail].x = nx; que[tail].y = ny;
    135       dst[nx][ny] = dst[x][y] + 1;
    136       vi[nx][ny] = true;
    137     }
    138  
    139     ++ head;
    140   }
    141 }
    142  
    143 void insert(int from, int to) {
    144   ++ cnt;
    145   edges[cnt].to = to;
    146   edges[cnt].next = head[from];
    147   head[from] = cnt;
    148 }
    149  
    150 void Solve(){
    151   dx[1] = dx[2] = a; dx[3] = dx[4] = -a; dx[5] = dx[6] = b; dx[7] = dx[8] = -b;
    152   dy[1] = dy[3] = b; dy[2] = dy[4] = -b; dy[5] = dy[7] = a; dy[6] = dy[8] = -a;
    153  
    154   for(int i = 1; i <= k; ++ i) {
    155     bfs(stx[i], sty[i]);
    156     for(int j = 1; j <= k; ++ j) {
    157       insert(i, j);
    158       if(!vi[edx[j]][edy[j]])
    159         w[i][j] = -oo;
    160       else
    161         w[i][j] = -dst[edx[j]][edy[j]];
    162     }
    163   }
    164  
    165 }
    166  
    167 void Output() {
    168   printf("%d
    ", -bsyx.km());
    169 }
    170  
    171 #define ONLINE_JUDGE
    172 int main() {
    173 #ifndef ONLINE_JUDGE
    174   freopen("chess.in", "r", stdin);
    175   freopen("chess.out", "w", stdout);
    176 #endif
    177  
    178   Input();
    179   Solve();
    180   Output();
    181  
    182 #ifndef ONLINE_JUDGE
    183   fclose(stdin); fclose(stdout);
    184 #endif
    185  
    186   return 0;
    187 }
    BZOJ 3008

    题9: BZOJ 1070修车

    M个技术人员和N个车,每个人修每个车都有不同的时刻,而且在同一个时间内,一个人只能修一辆车。问所有车都被修完的情况下,最小的平均等待时候是多少。

    分析:假设三个车ABC都找第一个人修,我们假设A是第一个修的,那么修完A的时候为Wa,另外两个等待的时候为2*Wa,第二个。如果我们假设第二个修的是A,那么修完A的时候,另一个等待的时间是Wa。如果最后修的是A,那么最后只有修的时间Wa。所以我们对一个人拆点,一个人拆成n个点,第i个车向第j个连j*cost的边。跑KM。注意左边的点和右边的点可能不相等,所以这是一个左右不等的KM。注意写法。

      1 #include <bits/stdc++.h>
      2  
      3 using namespace std;
      4  
      5 const int N = 600;
      6 const int M = 100000 + 5;
      7 const int oo = 0x3f3f3f3f;
      8  
      9 int n, m, cnt = 0;
     10 int nx, ny;
     11 int w[N][N], head[N];
     12  
     13  
     14 struct Edge {
     15   int to, next;
     16 }edges[M];
     17  
     18 struct KM {
     19   int lx[N], ly[N], sx[N], by[N], st[N], g[N];
     20   int tim;
     21  
     22   KM() {
     23     tim = 0;
     24     memset(by, 0, sizeof by);
     25     memset(sx, 0, sizeof sx);
     26   }
     27  
     28   void clear() {
     29     memset(g, 0, sizeof g);
     30     memset(lx, 0x80, sizeof lx);
     31     memset(ly, 0, sizeof ly);
     32   }
     33  
     34   bool find(int u) {
     35     sx[u] = tim;
     36     for(int i = head[u]; i; i = edges[i].next) {
     37       int v = edges[i].to;
     38  
     39       if(by[v] == tim) continue;
     40  
     41       int t = lx[u] + ly[v] - w[u][v];
     42  
     43       if(!t) {
     44         by[v] = tim;
     45         if(!g[v] || find(g[v])) {
     46           g[v] = u;
     47           return true;
     48         }
     49       }
     50       else {
     51         st[v] = min(st[v], t);
     52       }
     53     }
     54     return false;
     55   }
     56  
     57   int km() {
     58     clear();
     59     for(int i = 1; i <= nx; ++ i) {
     60       for(int j = 1; j <= ny; ++ j) {
     61         lx[i] = max(lx[i], w[i][j]);
     62       }
     63     }
     64     for(int i = 1; i <= nx; ++ i) {
     65       memset(st, 0x3f, sizeof st);
     66       for(;;) {
     67         ++ tim;
     68         if(find(i)) break;
     69  
     70         int d = oo;
     71  
     72         for(int j = 1; j <= ny; ++ j) {
     73           if(by[j] != tim) {
     74             d = min(st[j], d);
     75           }
     76         }
     77         for(int j = 1; j <= nx; ++ j) {
     78           if(sx[j] == tim) lx[j] -= d;
     79         }
     80         for(int j = 1; j <= ny; ++ j) {
     81           if(by[j] == tim) ly[j] += d;
     82           else st[j] -= d;
     83         }
     84       }
     85     }
     86  
     87     int res = 0;
     88  
     89     for(int i = 1; i <= ny; ++ i) {
     90       res += w[g[i]][i];
     91     }
     92  
     93     return res;
     94   }
     95 }bsyx;
     96  
     97 void insert(int from, int to) {
     98   ++ cnt;
     99   edges[cnt].to = to;
    100   edges[cnt].next = head[from];
    101   head[from] = cnt;
    102      
    103 }
    104  
    105 void Input() {
    106   int cost;
    107    
    108   scanf("%d%d", &m, &n);
    109   nx = n; ny = n * m;
    110   for(int i = 1; i <= n; ++ i) {
    111     int tmp = 0;
    112     for(int j = 1; j <= m; ++ j) {
    113       scanf("%d", &cost);
    114  
    115       for(int k = 1; k <= n; ++ k) {
    116         w[i][++ tmp] = -cost * k;
    117         insert(i, tmp);
    118       }
    119     }
    120   }
    121 }
    122  
    123 void Output() {
    124   printf("%.2lf
    ", (double) -bsyx.km() / n);
    125 }
    126  
    127 int main() {
    128   Input();
    129   Output();
    130  
    131   return 0;
    132 }
    BZOJ 1070

    题10: POJ 3686 The Windy's

    和题9一样的。

      1 #include <cmath>
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstdio>
      5 #include <cstring>
      6 #include <algorithm>
      7 
      8 using namespace std;
      9 
     10 
     11 const int N = 2500 + 5;
     12 const int M = 150000 + 5;
     13 const int oo = 0x3f3f3f3f;
     14 
     15 int n, m, cnt = 0, nx, ny;
     16 int tmp[N][N], w[N][N];
     17 int head[N];
     18 
     19 struct Edge {
     20   int to, next;
     21 }edges[M<<1];
     22 
     23 struct KM {
     24   int tim;
     25   int lx[N], ly[N], sx[N], by[N], st[N], g[N];
     26 
     27   KM() {
     28     tim = 0;
     29     memset(sx, 0, sizeof sx);
     30     memset(by, 0, sizeof by);
     31   }
     32 
     33   void clear() {
     34     memset(g, 0, sizeof g);
     35     memset(lx, 0x80, sizeof lx);
     36     memset(ly, 0, sizeof ly);
     37   }
     38 
     39   bool find(int u) {
     40     sx[u] = tim;
     41 
     42     for(int i = head[u]; i; i = edges[i].next) {
     43       int v = edges[i].to;
     44 
     45       if(by[v] == tim) continue;
     46 
     47       int t = lx[u] + ly[v] - w[u][v];
     48 
     49       if(!t) {
     50         by[v] = tim;
     51         if(!g[v] || find(g[v])) {
     52           g[v] = u;
     53           return true;
     54         }
     55       }
     56       else {
     57         st[v] = min(st[v], t);
     58       }
     59     }
     60     return false;
     61   }
     62 
     63   int km() {
     64     clear();
     65     for(int i = 1; i <= nx; ++ i) {
     66       for(int j = 1; j <= ny; ++ j) {
     67         lx[i] = max(lx[i], w[i][j]);
     68       }
     69     }
     70     for(int i = 1; i <= nx; ++ i) {
     71       memset(st, 0x3f, sizeof st);
     72       for(;;) {
     73         ++ tim;
     74         if(find(i)) break;
     75 
     76         int d = oo;
     77 
     78         for(int j = 1; j <= ny; ++ j) {
     79           if(by[j] != tim) {
     80             d = min(st[j], d);
     81           }
     82         }
     83         for(int j = 1; j <= nx; ++ j) {
     84           if(sx[j] == tim) lx[j] -= d;
     85         }
     86         for(int j = 1; j <= ny; ++ j) {
     87           if(by[j] == tim) ly[j] += d;
     88           else st[j] -= d;
     89         }
     90       }
     91     }
     92 
     93     int res = 0;
     94 
     95     for(int i = 1; i <= ny; ++ i) {
     96       res += w[g[i]][i];
     97     }
     98 
     99     return res;
    100   }
    101 }bsyx;
    102 
    103 void insert(int from, int to) {
    104   ++ cnt;
    105   edges[cnt].to = to;
    106   edges[cnt].next = head[from];
    107   head[from] = cnt;
    108 }
    109 
    110 void Input() {
    111   scanf("%d%d", &n, &m);
    112   nx = n; ny = n * m;
    113   for(int i = 1; i <= n; ++ i) {
    114     for(int j = 1; j <= m; ++ j) {
    115       scanf("%d", &tmp[i][j]);
    116     }
    117   }
    118 }
    119 
    120 void Solve() {
    121   cnt = 0;
    122   memset(head, 0, sizeof head);
    123 
    124   for(int i = 1; i <= n; ++ i) {
    125     int temp = 0;
    126 
    127     for(int j = 1; j <= m; ++ j) {
    128       for(int k = 1; k <= n; ++ k) {
    129         w[i][++ temp] = -tmp[i][j] * k;
    130         insert(i, temp);
    131       }
    132     }
    133   }
    134 }
    135 
    136 void Output() {
    137   printf("%.6lf
    ", (double) -bsyx.km() / n);
    138 }
    139 
    140 int main() {
    141   int t;
    142 
    143   scanf("%d", &t);
    144 
    145   while(t --) {
    146     Input();
    147     Solve();
    148     Output();
    149   }
    150 
    151   return 0;
    152 }
    POJ 3686

    题11: POJ 3565 Ants

    平面上N个白点N个黑点,求在最小距离的情况下两两相配的一个方案。

    只要证明所以匹配不会出现交叉的情况就好了。这是很容易证明的。

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <cmath>
      7 
      8 using namespace std;
      9 
     10 const int N = 200 + 5;
     11 const int M = 10000 + 5;
     12 const double oo = 1000000000;
     13 const double eps = 1e-6;
     14 
     15 int n, cnt = 0;
     16 int head[N], ans[N];
     17 double x[N], y[N], w[N][N];
     18 
     19 
     20 struct Edge {
     21   int to, next;
     22 }edges[M];
     23 
     24 struct KM {
     25   int tim;
     26   int sx[N], by[N], g[N];
     27   double lx[N], ly[N], st[N];
     28 
     29   KM() {
     30     tim = 0;
     31     memset(sx, 0, sizeof sx);
     32     memset(by, 0, sizeof by);
     33   }
     34 
     35   void clear() {
     36     memset(g, 0, sizeof g);
     37     for(int i = 0; i <= n; ++ i) lx[i] = -2139062144.00;
     38     memset(ly, 0, sizeof ly);
     39   }
     40 
     41   bool find(int u) {
     42     sx[u] = tim;
     43     for(int i = head[u]; i; i = edges[i].next) {
     44       int v = edges[i].to;
     45 
     46       if(by[v] == tim) continue;
     47 
     48       double t = lx[u] + ly[v] - w[u][v];
     49 
     50       if(fabs(t) < eps) {
     51         by[v] = tim;
     52         if(!g[v] || find(g[v])) {
     53           g[v] = u;
     54           return true;
     55         }
     56       }
     57       else {
     58         st[v] = min(st[v], t);
     59       }
     60     }
     61     return false;
     62   }
     63 
     64   void km() {
     65     clear();
     66     for(int i = 1; i <= n; ++ i) {
     67       for(int j = 1;j <= n; ++ j) {
     68         lx[i] = max(lx[i], w[i][j]);
     69       }
     70     }
     71     for(int i = 1; i <= n; ++ i) {
     72       for(int j = 0; j <= n; ++ j)
     73         st[j] = 1061109567.00;
     74       for(;;) {
     75         ++ tim;
     76         if(find(i)) break;
     77 
     78         double d = 1000000000;
     79 
     80         for(int j = 1; j <= n; ++ j) {
     81           if(by[j] != tim) {
     82             d = min(st[j], d);
     83           }
     84         }
     85         for(int j = 1; j <= n; ++ j) {
     86           if(sx[j] == tim) lx[j] -= d;
     87           if(by[j] == tim) ly[j] += d;
     88           else st[j] -= d;
     89         }
     90       }
     91     }
     92   }
     93 }bsyx;
     94 
     95 double dist(int a, int b) {
     96   return sqrt((x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]));
     97 }
     98 
     99 void insert(int from, int to) {
    100   ++ cnt;
    101   edges[cnt].to = to;
    102   edges[cnt].next = head[from];
    103   head[from] = cnt;    
    104 }
    105 
    106 void Input() {
    107   scanf("%d", &n);
    108   for(int i = 1; i <= n; ++ i) {
    109     scanf("%lf%lf", &x[i], &y[i]);
    110   }
    111   for(int i = 1; i <= n; ++ i) {
    112     scanf("%lf%lf", &x[i + n], &y[i + n]);
    113   }
    114 }
    115 
    116 void Solve() {
    117   for(int i = 1; i <= n; ++ i) {
    118     for(int j = 1; j <= n; ++ j) {
    119       insert(i, j);
    120       w[i][j] = -dist(i, j + n);
    121     }
    122   }
    123   bsyx.km();
    124 }
    125 
    126 void Output() {
    127   for(int i = 1; i <= n; ++ i) {
    128     ans[bsyx.g[i]] = i;
    129   }
    130   for(int i = 1; i <= n; ++ i) {
    131     printf("%d
    ", ans[i]);
    132   }
    133 }
    134 
    135 int main() {
    136   Input();
    137   Solve();
    138   Output();
    139 
    140   return 0;
    141 }
    POJ 3565

    题12: HDU 3488

    模板题。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int N = 200 + 5;
      6 const int M = 30000 + 5;
      7 const int oo = 0x7fffffff;
      8 
      9 int n, m;
     10 int head[N], w[N][N];
     11 int cnt = 0;
     12 
     13 struct Edge{
     14   int to, next;
     15 }edges[M];
     16 
     17 struct KM{
     18   int tim;
     19   int lx[N], ly[N], sx[N], by[N], st[N], g[N];
     20 
     21   KM(){
     22     tim = 0;
     23     memset(sx, 0, sizeof sx);
     24     memset(by, 0, sizeof by);
     25   }
     26   
     27   inline void clear(){
     28     memset(g, 0, sizeof g);
     29     memset(lx, 0x80, sizeof lx);
     30     memset(ly, 0, sizeof ly);
     31   }
     32 
     33   inline bool find(int u){
     34     sx[u] = tim;
     35     for(int i = head[u]; i; i = edges[i].next){
     36       int v = edges[i].to;
     37 
     38       if(by[v] == tim) continue;
     39 
     40       int t = lx[u] + ly[v] - w[u][v];
     41 
     42       if(!t){
     43         by[v] = tim;
     44         if(!g[v] || find(g[v])){
     45           g[v] = u;
     46           return true;
     47         }
     48       }
     49       else{
     50         st[v] = min(st[v], t);
     51       }
     52     }
     53 
     54     return false;
     55   }
     56 
     57   inline int km(){
     58     clear();
     59     for(int i = 1; i <= n; ++ i){
     60       for(int j = 1; j <= n; ++ j){
     61         lx[i] = max(lx[i], w[i][j]);
     62       }
     63     }
     64     for(int i = 1; i <= n; ++ i){
     65       memset(st, 0x3f, sizeof st);
     66       for(;;){
     67         ++ tim;
     68         if(find(i)) break;
     69 
     70         int d = oo;
     71         
     72         for(int j = 1; j <= n; ++ j){
     73           if(by[j] != tim)
     74             d = min(d, st[j]);
     75         }
     76         for(int j = 1; j <= n; ++ j){
     77           if(sx[j] == tim) lx[j] -= d;
     78           if(by[j] == tim) ly[j] += d;
     79           else st[j] -= d;
     80         }
     81       }
     82     }
     83 
     84     int res = 0;
     85     
     86     for(int i = 1; i <= n; ++ i){
     87       res += w[g[i]][i];
     88     }
     89 
     90     return res;
     91   }
     92 }bsyx;
     93 
     94 void insert(int from, int to){
     95   ++ cnt;
     96   edges[cnt].to = to;
     97   edges[cnt].next = head[from];
     98   head[from] = cnt;
     99 }
    100 
    101 void Input(){
    102   int x, y, z;
    103   
    104   cnt = 0;
    105   memset(head, 0, sizeof head);
    106   memset(w, 0x80, sizeof w);
    107   
    108   scanf("%d%d", &n, &m);
    109   for(int i = 1; i <= m; ++ i){
    110     scanf("%d%d%d", &x, &y, &z);
    111     insert(x, y);
    112     w[x][y] = max(w[x][y], -z);
    113   }
    114 }
    115 
    116 void Output(){
    117   printf("%d
    ", -bsyx.km());
    118 }
    119 
    120 int main(){
    121   int t;
    122 
    123   scanf("%d", &t);
    124 
    125   while(t --){
    126     Input();
    127     Output();
    128   }
    129 
    130   return 0;
    131 }
    HDU 3488
  • 相关阅读:
    2019年书单
    JMeter报错:Address already in use : connect
    读书笔记——弗洛伊德《梦的解析》
    Python3学习之路~10.3 论事件驱动与异步IO
    Python3学习之路~10.2 协程、Greenlet、Gevent
    nmon使用问题汇总(不定期更新)
    ( VIJOS )VOJ 1049 送给圣诞夜的礼品 矩阵快速幂
    POJ3233 Matrix Power Series 矩阵乘法
    NYOJ 298 点的变换 矩阵乘法
    HDU 5834 Magic boy Bi Luo with his excited tree 树形dp
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5161589.html
Copyright © 2011-2022 走看看