zoukankan      html  css  js  c++  java
  • UVA 1663 Purifying Machine (二分图匹配,最大流)

    题意:

      给m个长度为n的模板串,模板串由0和1和*三种组成,且每串至多1个*,代表可0可1。模板串至多匹配2个串,即*号改成0和1,如果没有*号则只能匹配自己。问:模板串可以缩减为几个,同样可以匹配原来m个串同样能匹配的所有串。

    思路:

      差点想不出是二分图匹配了。

      将原来m个串所能匹配的串给取出来放到集合中(记得去重),编上号。并为他们黑白着色,源点到白色点有容量1的边,黑色点到汇点有容量为1的边,对于该白色点所能匹配的所有黑色点,都有一条容量为1的边。跑一次最大流,得知匹配对数,这些匹配的都只用1个模板串,不匹配的独用一个模板串。

    //#include <bits/stdc++.h>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <deque>
    #include <set>
    #include <algorithm>
    #define LL long long
    #define pii pair<int,int>
    #define INF 0x7f7f7f7f
    using namespace std;
    const int N=1010;
    int n, m, up;
    char s[N][13];
    int col[N*2], path[N*2], flow[N*2], edge_cnt;
    vector<int> vect[N*2];
    vector<int> vec[N*2];
    
    
    struct node
    {
        int from, to, cap, flow;
        node(){};
        node(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){};
    }edge[2100000];
    
    void add_node(int from,int to,int cap,int flow)
    {
        edge[edge_cnt]=node(from,to,cap,flow);
        vect[from].push_back(edge_cnt++);
    }
    
    bool ismatch(string &a,string &b)   //只有一个位不同即为匹配
    {
        int cnt=0;
        for(int i=0; i<n; i++) 
            if( a[i]!=b[i] )    cnt++;
        if(cnt==1)  return true;
        else    return false;
    }
    
    
    void color(int s,int c)
    {
        col[s]=c;
        for(int i=0; i<vec[s].size(); i++)
        {
            int t=vec[s][i];
            if(!col[t]) color(t,3-col[s]);
        }
    }
    
    set<string> sett;
    string str[N*2];
    int build_graph()
    {
        //把包含*号的拆成两个数字,再转int,可能有重复。
        sett.clear();
        for(int i=0; i<m; i++)
        {
            int j=0;
            for(; j<n; j++)
            {
                if(s[i][j]=='*')
                {
                    s[i][j]='0';
                    sett.insert( string(s[i]) );    //重复的自动去掉
                    s[i][j]='1';
                    sett.insert( string(s[i]) );
                    break;
                }
            }
            if(j==n)  sett.insert( string(s[i]) );
        }
    
        up=1;
        for(set<string>::iterator it=sett.begin(); it!=sett.end(); it++)
            str[up++]=*it;
    
        for(int i=0; i<=up+5; i++) vect[i].clear(),vec[i].clear();//第二个vec是为了着色用的
    
        for(int i=1; i<up; i++)        //匹配建无向图,着色用
        {
            for(int j=i+1; j<up; j++)
                if(ismatch(str[i],str[j]))
                {
                    vec[i].push_back(j);
                    vec[j].push_back(i);
                }
        }
    
    
    
        //黑白着色
        memset(col,0,sizeof(col));
        for(int i=1; i<up; i++)    if(!col[i]) color(i,1);
    
        //添加源点and汇点,重新建图
        memset(edge,0,sizeof(edge));
        edge_cnt=0;
        for(int i=1; i<up; i++)
        {
            if(col[i]==1)   //0是源点
            {
                add_node(0,i,1,0);
                add_node(i,0,0,0);
                for(int j=0; j<vec[i].size(); j++)  //相邻的点颜色不同
                {
                    int q=vec[i][j];
                    add_node(i,q,1,0);
                    add_node(q,i,0,0);
                }
            }
            if(col[i]==2)   //up是汇点
            {
                add_node(i,up,1,0);
                add_node(up,i,0,0);
            }
        }
    }
    
    int BFS(int s,int e)
    {
        deque<int> que(1,s);
        flow[s]=INF;
        while(!que.empty())
        {
            int x=que.front(); que.pop_front();
            for(int i=0; i<vect[x].size(); i++)
            {
                node e=edge[vect[x][i]];
                if(e.cap>e.flow && !flow[e.to])
                {
                    path[e.to]=vect[x][i];
                    flow[e.to]=min(flow[e.from], e.cap-e.flow);
                    que.push_back(e.to);
                }
            }
            if(flow[e]) break;
        }
        return flow[e];
    }
    
    int max_flow(int s,int e)
    {
        int ans_flow=0;
        while(true)
        {
            memset(flow,0,sizeof(flow));
            memset(path,0,sizeof(path));
            int tmp=BFS(s,e);
            if(!tmp)    return ans_flow;
            ans_flow+=tmp;
    
            int ed=e;
            while(ed!=s)
            {
                int t=path[ed];
                edge[t].flow+=tmp;
                edge[t^1].flow-=tmp;
                ed=edge[t].from;
            }
        }
    }
    
    int main()
    {
        //freopen("input.txt", "r", stdin);
        char c;
        while(scanf("%d%d",&n,&m), n+m)
        {
            for(int i=0; i<m; i++)//输入
            {
                for(int j=0; j<n; )
                {
                    c=getchar();
                    if(c=='*' || c=='0' || c=='1')    s[i][j++]=c;
                }
                s[i][n]='';
            }
            build_graph();//建图
            printf("%d
    ",up-1-max_flow(0,up));
        }
        return 0;
    }
    AC代码
  • 相关阅读:
    Centos下一个server安装的版本号mysql
    android 玩愤怒的小鸟等游戏的时候全屏TP失败
    6.8 一般处理语言
    [AC自己主动机+可能性dp] hdu 3689 Infinite monkey theorem
    POJ1185:火炮(减少国家)
    教你如何下载音乐的网站只试镜
    实现js呼叫流行
    [Angular 2] Async Http
    [Typescript] Function defination
    [React] React Router: setRouteWillLeaveHook
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4667582.html
Copyright © 2011-2022 走看看