• UVa 753 (二分图最大匹配) A Plug for UNIX


    题意:

    有n个插座,m个设备以及k种转化器(每种转化器视为有无限个)。

    转换器A->B可以将A类型的插头转化成B类型的插头,所以可以插在B类型的插座上。

    求最少剩多少不匹配的设备。

    分析:

    抛开转换器不讲,插头插在插座上就是一个最大二分图匹配。

    可以用最大流的算法,增加一个连接每个插头的源点s和连接每个插座的汇点t,每条弧容量都为1.

    然后求最大流量,就是二分图的最大基数匹配。

    既然有了转换器,一种插头可以用转换器转换成多种类型的插头,所以可以Floyd一次,求出每种插头可以转换成的所有的插头类型。

    然后构二分图,求最大匹配即可。

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 const int maxn = 400 + 10;
      6 
      7 vector<string> names;
      8 int ID(const string& s)
      9 {
     10     for(int i = 0; i < names.size(); ++i)
     11         if(names[i] == s) return i;
     12     names.push_back(s);
     13     return names.size() - 1;
     14 }
     15 
     16 int n, m, k;
     17 bool d[maxn][maxn];
     18 int target[maxn], device[maxn];
     19 
     20 const int INF = 1000000000;
     21 
     22 struct Edge
     23 {
     24     int from, to, cap, flow;
     25     Edge(int u=0, int v=0, int c=0, int f=0):from(u), to(v), cap(c), flow(f) {}
     26 };
     27 
     28 struct EdmondsKarp
     29 {
     30     int n, m;
     31     vector<Edge> edges;
     32     vector<int> G[maxn];
     33     int a[maxn];
     34     int p[maxn];
     35 
     36     void Init(int n)
     37     {
     38         for(int i = 0; i < n; ++i) G[i].clear();
     39         edges.clear();
     40     }
     41 
     42     void AddEdge(int from, int to, int cap)
     43     {
     44         edges.push_back(Edge(from, to, cap, 0));
     45         edges.push_back(Edge(to, from, 0, 0));
     46         m = edges.size();
     47         G[from].push_back(m-2);
     48         G[to].push_back(m-1);
     49     }
     50 
     51     int MaxFlow(int s, int t)
     52     {
     53         int flow = 0;
     54         for(;;)
     55         {
     56             memset(a, 0, sizeof(a));
     57             queue<int> Q;
     58             Q.push(s);
     59             a[s] = INF;
     60             while(!Q.empty())
     61             {
     62                 int x = Q.front(); Q.pop();
     63                 for(int i = 0; i < G[x].size(); ++i)
     64                 {
     65                     Edge& e = edges[G[x][i]];
     66                     if(!a[e.to] && e.cap > e.flow)
     67                     {
     68                         p[e.to] = G[x][i];
     69                         a[e.to] = min(a[x], e.cap - e.flow);
     70                         Q.push(e.to);
     71                     }
     72                 }
     73                 if(a[t]) break;
     74             }
     75             if(!a[t]) break;
     76             for(int u = t; u != s; u = edges[p[u]].from)
     77             {
     78                 edges[p[u]].flow += a[u];
     79                 edges[p[u]^1].flow -= a[u];
     80             }
     81             flow += a[t];
     82         }
     83         return flow;
     84     }
     85 };
     86 
     87 EdmondsKarp g;
     88 
     89 int main()
     90 {
     91     //freopen("in.txt", "r", stdin);
     92     int T;
     93     scanf("%d", &T);
     94     while(T--)
     95     {
     96         names.clear();
     97         memset(d, 0, sizeof(d));
     98         string s1, s2;
     99         scanf("%d", &n);
    100         for(int i = 0; i < n; ++i) { cin >> s1; target[i] = ID(s1); }
    101         scanf("%d", &m);
    102         for(int i = 0; i < m; ++i) { cin >> s1 >> s2; device[i] = ID(s2); }
    103         scanf("%d", &k);
    104         for(int i = 0; i < k; ++i) { cin >> s1 >> s2; d[ID(s1)][ID(s2)] = true;    }
    105         //Floyd
    106         int V = names.size();
    107         for(int k = 0; k < V; ++k)
    108             for(int i = 0; i < V; ++i)
    109                 for(int j = 0; j < V; ++j)
    110                     d[i][j] |= d[i][k] && d[k][j];
    111 
    112         //Build Graph
    113         g.Init(V+2);
    114         for(int i = 0; i < m; ++i) g.AddEdge(V, device[i], 1);//源点到每个设备
    115         for(int i = 0; i < n; ++i) g.AddEdge(target[i], V+1, 1);//每个插座到汇点
    116         for(int i = 0; i < m; ++i)
    117             for(int j = 0; j < n; ++j)
    118                 if(d[device[i]][target[j]]) g.AddEdge(device[i], target[j], INF);
    119         int ans = g.MaxFlow(V, V+1);
    120         printf("%d
    ", m-ans);
    121         if(T) puts("");
    122     }
    123 
    124     return 0;
    125 }
    代码君

    紫书后面又介绍了一种更简单的做法,就是直接把k种转换器对应的k条弧加到图中去,然后求最大流。

    代码就不贴了,=_=||

  • 相关阅读:
    vijos1198:最佳课题选择
    vijos1071:新年趣事之打牌
    vijos1153:猫狗大战
    bzoj3594: [Scoi2014]方伯伯的玉米田
    bzoj2753: [SCOI2012]滑雪与时间胶囊
    bzoj1923: [Sdoi2010]外星千足虫
    bzoj2783: [JLOI2012]树
    bzoj4590: [Shoi2015]自动刷题机
    bzoj4580: [Usaco2016 Open]248
    bzoj4579: [Usaco2016 Open]Closing the Farm
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4280403.html
Copyright © 2020-2023  润新知