UVA - 753 A Plug for UNIX

1.A - A Plug for UNIX

题意:

有n个插座,m个设备和k种转换器,每种转换器都由无限多。已知每个插座的类型,每个设备的插头类型,以及每种转换器的插头类型和插座类型。插头和插座类型都不超过24个字母表示,插头只能插到对应类型名称相同的插座。

问:要求插得设备尽量多,问最少剩几个不匹配的设备。

按照紫书上的思路可以有两种解法:

  • 第一种

首先建图,图的节点表示插头类型,图的边表示转换器。利用floyd算法求出每种插头可以转换的情况(注意转换器是可以有无限多的);
其次构造网络:设设备i的插头类型为devices[i],插座i对应的插头类型为target[i],源点s到所有的devices[i]连一条弧,容量为1,所有target[i]到汇点t连接一条弧,容量为1;对于设备插座deveces[i]和插座的对应插头类型target[j],如果devices[i]可以转换为target[j],则连接一条弧,容量无限制;这样就转化为求源点s到汇点t的最大流。

再求最大流的时候,紫书上介绍的是Edmonds-Karp算法的原理,但是比赛一般用的是ISAP和dinic,这两个算法在紫书的训练指南上有介绍,模板可以借鉴匡斌的模板,对于ISAP和dinic可以不详细探究他的原理,当做STL一样的东西会用就行。

  • 第二种
    第二种是把所有的插头类型都标出来,如果存在一条devices[i]到target[j]的转换器,则连接一条弧,容量无穷大。最后也求s-t的最大流
    (第二种方法可能更像是二分图匹配)

复习一下二分图匹配:
二分图匹配有两种问题

1.针对无权图
求包含边数最多的匹配。(而二分图的最大基数匹配)
思路是增加源点跟汇点,求s-t的最大流

2.针对带权图
求边权和尽量大的匹配
分为两类:

  • 完美匹配
    每个点都要匹配到

  • 不对边的数量做要求
    只要求最大边权和

(遗忘了的话,课后自主复习一下)


解题代码:

#include <bits/stdc++.h>
using namespace std;
#define clr(a,x) memset(a, x, sizeof(a))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin ios_base::sync_with_stdio(0);cin.tie(0);
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;

const int maxn = 405;

struct Edge
{
    int from, to, cap, flow;
    Edge(int u, int v, int c, int f): from(u), to(v), cap(c), flow(f) {}
};
struct Dinic
{
    int n, m, s, t;         //结点数,边数(包括反向弧),源点编号和汇点编号
    vector<Edge> edges;     //边表。edge[e]和edge[e^1]互为反向弧
    vector<int> G[maxn];    //邻接表,G[i][j]表示节点i的第j条边在e数组中的序号
    bool vis[maxn];         //BFS使用
    int d[maxn];            //从起点到i的距离
    int cur[maxn];          //当前弧下标
    void init(int n)
    {
        this->n = n;
        for (int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }
    void AddEdge(int from, int to, int cap)
    {
        edges.pb(Edge(from, to, cap, 0));
        edges.pb(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].pb(m - 2);
        G[to].pb(m - 1);
    }
    bool BFS()
    {
        clr(vis, 0);
        clr(d, 0);
        queue<int> q;
        q.push(s);
        d[s] = 0;
        vis[s] = 1;
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            for (int i = 0; i < G[x].size(); i++)
            {
                Edge& e = edges[G[x][i]];
                if (!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[x] + 1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x, int a)
    {
        if (x == t || a == 0) return a;
        int flow = 0, f;
        for (int& i = cur[x]; i < G[x].size(); i++)
        {
            //从上次考虑的弧
            Edge& e = edges[G[x][i]];
            if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
            {
                e.flow += f;
                edges[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }
    int Maxflow(int s, int t)
    {
        this->s = s;
        this->t = t;
        int flow = 0;
        while (BFS())
        {
            clr(cur, 0);
            flow += DFS(s, INF);
        }
        return flow;
    }
} ans;

map <string, int> M;

int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    fastin
    int T, n, m, k;
    cin >> T;
    while (T--)
    {
        M.clear();
        cin >> n;
        int s = 0, t = 1;
        ans.init(maxn);
        int tot = 2;
        string tmp, dev;
        while (n--)
        {
            //插座->超级汇点
            cin >> tmp;
            if (!M[tmp]) M[tmp] = tot++;
            ans.AddEdge(M[tmp], t, 1);
        }
        cin >> m;
        for (int i = 0; i < m; i++)
        {
            //超级源点->电器
            cin >> dev >> tmp;
            if (!M[tmp]) M[tmp] = tot++;
            ans.AddEdge(s, M[tmp], 1);
        }
        cin >> k;
        string u, v;
        while (k--)
        {
            //转换器
            cin >> u >> v;
            if (!M[u]) M[u] = tot++;
            if (!M[v]) M[v] = tot++;
            ans.AddEdge(M[u], M[v], INF);
        }
        cout << m - ans.Maxflow(s, t) << endl;
        if (T) cout << endl;
    }
    return 0;
}
posted @ 2018-07-13 16:46  Bryce1010  阅读(86)  评论(0编辑  收藏  举报