UVa 1663 – Purifying Machine [最大流+匹配]

点击打开vjudge题目链接

题意:给m个长度为n的模板串。每个模板串包含字符0,1和最多一个’*’,其中星号能够匹配0或1。例如01*可以匹配010和011两个串。你的任务是改写这个模板集合,使得模板的个数最少。

分析:将所有的模板串解析成原来的01串,去重保存。然后拆点法+编号,从原点s到每个串加容量为1的边,从每个串到汇点t加容量为1的边,每个串分成1~N和N+1~2N,然后能够匹配的串加从左到右容量为1的边。最后用最大流算法(无奈用匈牙利算法一直WA…)求出最大匹配来,答案就是总串数-最大流/2.

C++代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5120, inf = 0x3f3f3f3f;
vector<string> v;
int N, M;

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 EdmondsKarp{
    vector<Edge> edges;
    vector<int> G[maxn];
    int a[maxn], p[maxn];

    void init() {
        for(int i = 0; i < maxn; ++i)
            G[i].clear();
        edges.clear();
    }
    void addEdge(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        int m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    int maxFlow(int s, int t) {
        int flow = 0;
        while(true) {
            memset(a, 0, sizeof(a));
            queue<int> qu;
            qu.push(s); a[s] = inf;
            while(!qu.empty()) {
                int x = qu.front(); qu.pop();
                for(unsigned i = 0; i < G[x].size(); ++i) {
                    Edge & e = edges[G[x][i]];
                    if(!a[e.to] && e.cap > e.flow) {
                        p[e.to] = G[x][i];
                        a[e.to] = min(a[x], e.cap - e.flow);
                        qu.push(e.to);
                    }
                }
                if(a[t]) break;
            }
            if(!a[t]) break;
            for(int u = t; u != s; u = edges[p[u]].from) {
                edges[p[u]].flow += a[t];
                edges[p[u]^1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
}EK;

void input() {
    v.clear();
    for(int i = 0; i < M; ++i) {
        string s; cin >> s;
        for(int j = 0; j != s.size(); ++j) {
            auto p = s.find('*');
            if(p != string::npos) {
                v.push_back(s.replace(p, 1, "0"));
                v.push_back(s.replace(p, 1, "1"));
            }
            else v.push_back(s);
        }
    }
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
}

bool canMerge(const string &a, const string &b) {
    int cnt = 0;
    for(int i = 0; i != a.size(); ++i) {
        if(a[i] != b[i]) ++cnt;
        if(cnt > 1) break;
    }
    return cnt == 1;
}

void build() {
    EK.init();
    for(int i = 0; i < v.size(); ++i) {
        EK.addEdge(0, i+1, 1);
        EK.addEdge(v.size()+i+1, 2*v.size()+1, 1);
    }
    for(int i = 0; i < v.size(); ++i)
        for(int j = i + 1; j < v.size(); ++j)
            if(canMerge(v[i], v[j])) {
                EK.addEdge(i+1, v.size()+j+1, 1);
                EK.addEdge(j+1, v.size()+i+1, 1);
            }
}

int main() {
    ios::sync_with_stdio(false);
    while(cin >> N >> M, N || M) {
        input();
        build();
        cout << v.size() - EK.maxFlow(0, 2*v.size()+1)/2 << endl;
    }
    return 0;
}

欢迎留言