zoukankan      html  css  js  c++  java
  • URAL1099 Work Scheduling —— 一般图匹配带花树

    题目链接:https://vjudge.net/problem/URAL-1099

    1099. Work Scheduling

    Time limit: 0.5 second
    Memory limit: 64 MB
    There is a certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to be scheduled in pairs so that each pair guards in a different night. The junkyard CEO ordered you to write a program which given the guards characteristics determines the maximum amount of scheduled guards (the rest will be fired). Please note that each guard can be scheduled with only one of his colleagues and no guard can work alone.

    Input

    The first line of the input contains one number N ≤ 222 which is a number of night guards. Unlimited number of lines consisting of unordered pairs (ij) follow, each such pair means that guard #i and guard #j can work together, because it is possible to find uniforms that suit both of them (The junkyard uses different parts of uniforms for different guards i.e. helmets, pants, jackets. It is impossible to put small helmet on a guard with a big head or big shoes on guard with small feet). The input ends with Eof.

    Output

    You should output one possible optimal assignment. On the first line of the output write the even number C, the amount of scheduled guards. Then output C/2 lines, each containing 2 integers (ij) that denote that i and j will work together.

    Sample

    inputoutput
    3
    1 2
    2 3
    1 3
    
    2
    1 2
    

    题解:

    一般图匹配带花树的模板题。还是看不太懂,以后有时间再看看。

    有关怎么找到奇环:

    其中可以把最右边两个点看成是找到奇环时的两个点,其中root为他们的LCA。

    疑问1:什么要把花上的边的方向取反?

    疑问2:为什么在找奇环时要特判 v==start ?

    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cstdlib>
      5 #include <string>
      6 #include <vector>
      7 #include <map>
      8 #include <set>
      9 #include <queue>
     10 #include <sstream>
     11 #include <algorithm>
     12 using namespace std;
     13 const int INF = 2e9;
     14 const int MOD = 1e9+7;
     15 const int MAXM = 20+10;
     16 const int MAXN = 2e3+10;
     17 
     18 int N;
     19 bool graph[MAXN][MAXN];
     20 int match[MAXN];
     21 bool inque[MAXN], inpath[MAXN], inblos[MAXN];
     22 queue<int>q;
     23 int start, finish;
     24 int newbase, fa[MAXN], base[MAXN];
     25 
     26 int FindCommonAncester(int u, int v)   //仅仅是找LCA,并不修改任何值
     27 {
     28     memset(inpath, false, sizeof(inpath));
     29     while(true)
     30     {
     31         u = base[u];
     32         inpath[u] = true;
     33         if(u==start) break;
     34         u = fa[match[u]];
     35     }
     36     while(true)
     37     {
     38         v = base[v];
     39         if(inpath[v]) break;
     40         v = fa[match[v]];
     41     }
     42     return v;
     43 }
     44 
     45 void ResetTrace(int u)  //把fa的方向取反
     46 {
     47     int v;
     48     while(base[u]!=newbase) //匹配边、非匹配边交替出现
     49     {
     50         v = match[u];   //u--match[u]匹配边
     51         inblos[base[u]] = inblos[base[v]] = true;
     52         u = fa[v];      //v--fa[v]非匹配边
     53         if(base[u]!=newbase) fa[u] = v;
     54     }
     55 }
     56 
     57 void BloosomContract(int u, int v)
     58 {
     59     newbase = FindCommonAncester(u, v);
     60     memset(inblos, false, sizeof(inblos));
     61     ResetTrace(u);   //把u到LCA上的边取反
     62     ResetTrace(v);   //把v到LCA上的边取反
     63     if(base[u]!=newbase) fa[u] = v; //看不懂
     64     if(base[v]!=newbase) fa[v] = u;
     65 
     66     for(int tu = 1; tu<=N; tu++)
     67     if(inblos[base[tu]])
     68     {
     69         base[tu] = newbase;     //设置它属于的集合
     70         if(!inque[tu]) q.push(tu);  //在花中的点加入队列,因为与花中点相连的点还可以找增广路
     71     }
     72 }
     73 
     74 void FindAugmentingPath()
     75 {
     76     memset(inque, false, sizeof(inque));
     77     memset(fa, 0, sizeof(fa));
     78     for(int i = 1; i<=N; i++)
     79         base[i] = i;
     80     while(!q.empty()) q.pop();
     81     q.push(start);
     82     finish = 0;
     83 
     84     while(!q.empty())
     85     {
     86         int u = q.front(); q.pop();
     87 
     88         for(int v = 1; v<=N; v++)  //fa[u]--u是匹配边, u--v是未匹配边。
     89         if(graph[u][v] && base[u]!=base[v] && match[u]!=v )
     90         {
     91             //为什么要特判 v==start ?
     92             if( (v==start) || (match[v]>0 && fa[match[v]]>0))   //找到奇环。
     93                 BloosomContract(u, v);
     94             else if(fa[v]==0)   //v点在这次找增广路时没有被访问
     95             {
     96                 fa[v] = u;
     97                 if(match[v]>0)  //如果已经匹配了,则加入他的匹配点,继续找增广路。
     98                     q.push(match[v]);
     99                 else    //如果没有匹配,则找到了增广路。
    100                 {
    101                     finish = v;
    102                     return;
    103                 }
    104             }
    105         }
    106     }
    107 }
    108 
    109 void AugmentPath()
    110 {
    111     int u, v, w;
    112     u = finish;
    113     while(u>0)  //沿着增广路往回走,把匹配边和非匹配边取反
    114     {
    115         v = fa[u];
    116         w = match[v];
    117         match[v] = u;
    118         match[u] = v;
    119         u = w;
    120     }
    121 }
    122 
    123 void Edmonds()
    124 {
    125     memset(match, 0, sizeof(match));
    126     for(int u = 1; u<=N; u++)
    127     if(match[u]==0)
    128     {
    129         start = u;
    130         FindAugmentingPath();
    131         if(finish>0) AugmentPath();
    132     }
    133 }
    134 
    135 int main()
    136 {
    137     scanf("%d", &N);
    138     memset(graph, false, sizeof(graph));
    139     int u, v;
    140     while(scanf("%d%d", &u, &v)!=EOF)
    141         graph[u][v] = graph[v][u] = true;
    142 
    143     Edmonds();
    144     int sum = 0;
    145     for(int u = 1; u<=N; u++)
    146         if(match[u]>0) sum++;
    147     printf("%d
    ", sum);
    148     for(int u = 1; u<=N; u++)
    149         if(u<match[u])
    150             printf("%d %d
    ", u, match[u]);
    151 
    152     return 0;
    153 }
    View Code
  • 相关阅读:
    vim使用技巧
    排序
    2020-3-27 学习面向对象的笔记
    小圆圈第三章答案
    内置函数部分用法
    Pycharm快捷键
    小猿圈第二章答案
    Typora学习笔记
    AI的真实感
    Unity 横版2D移动跳跃问题——关于一段跳与二段跳
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7842588.html
Copyright © 2011-2022 走看看