POJ 2724 Purifying Machine(二分图最大匹配)
http://poj.org/problem?id=2724
题意:
给出m串长度为n的01串。有些串中可能包含*,这样的串可以表示两个串,*为1 和*为0。重复的算一种。比如题目中
*01
100
011
就代表了四个01串(注意输入的串需要判断重复)
001
101
100
011
现在我们需要消灭掉所有的01串,消灭方式有两种:
1一次消灭一个串。
2如果两个串的差别只有一位的话可以同时消灭这两个串。
问最少多少次操作可以消灭所有的01串
分析:
也就是给你一些不同的(判重之后)二进制串,每个串可以通过1次操作净化,也可以把两个只有1位不同的串通过1次操作联合净化.要我们求最少的操作次数.
我们把所有串按其中1的个数和是奇还是偶分成左右两个点集.
对于任意两个串,如果他们只有1位不同,那么就在他们之间连接一条无向边.(这两个串一定分别属于不同的点集)
由于串的总数是固定的,且一个串可以通过单独净化也可以通过联合净化.而我们向让净化的次数最少,我们自然想联合净化(即一次可以净化两个串)的次数尽量多了.
那么我们最多可以进行多少次联合净化呢? 这个数值==我们建立二分图的最大匹配边数.(想想是不是,因为一个串最多只能被净化一次)
假设总的不同串有n个,我们建立二分图的最大匹配数(即联合净化最大次数)为ans,那么我们总共需要n-ans次净化即可.(想想为什么)
当然本题也可以不用把串特意分成左右点集(本程序实现就是用的这种方式),我们只需要把原图翻倍,然后求翻倍图的最大匹配数ans,最后用n-ans/2即可.(类似于POJ1466:
http://blog.csdn.net/u013480600/article/details/38638219).
AC代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<string>
#include<iostream>
using namespace std;
const int maxn=1000+100;
struct Max_Match
{
int n;
vector<int> g[maxn];
bool vis[maxn];
int left[maxn];
void init(int n)
{
this->n=n;
for(int i=1;i<=n;i++) g[i].clear();
memset(left,-1,sizeof(left));
}
bool match(int u)
{
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v])
{
vis[v]=true;
if(left[v]==-1 || match(left[v]))
{
left[v]=u;
return true;
}
}
}
return false;
}
int solve()
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(match(i)) ++ans;
}
return ans;
}
}MM;
struct Node
{
string s;
bool link(Node& rhs)//判断两个string是否只相差1位
{
int num = 0;
for(int i=0;i<s.size(); i++)
if(s[i]!=(rhs.s)[i]) ++num;
return num==1;
}
}node[maxn];
int main()
{
int N,M;
while(scanf("%d%d",&N,&M)==2 && N)
{
int num=0;
set<string> st;//判重string
for(int i=1;i<=M;i++)
{
string s;
cin>>s;
if(s.find("*")!=-1)
{
int pos=s.find("*");
string s1(s),s2(s);
s1[pos]='0';
s2[pos]='1';
if(st.find(s1) == st.end())//s1与已有string不重复
{
st.insert(s1);
node[++num].s = s1;
}
if(st.find(s2) == st.end())//s2与已有string不重复
{
st.insert(s2);
node[++num].s = s2;
}
}
else
{
if(st.find(s) == st.end())
{
st.insert(s);
node[++num].s = s;
}
}
}
MM.init(num);
for(int i=1;i<=num;i++)
for(int j=1;j<=num;j++)if(i!=j)
if(node[i].link(node[j]))
MM.g[i].push_back(j);
printf("%d\n",num-MM.solve()/2);
}
return 0;
}
分享到:
相关推荐
poj openjudge 1111题最大正向匹配 提交ac
北大POJ1276-Cash Machine 解题报告+AC代码
初期: 一.基本算法: (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586) ... (5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020) (6)最大流的增广路算法(KM算法). (poj1459,poj3436) ......
【二分图顶点覆盖->最小割->最大流->Dinic算法求解】 解题报告+AC代码 http://hi.csdn.net/!s/WKVPR0 ----> 我的所有POJ解题报告 http://blog.csdn.net/lyy289065406/article/details/6642573
北大POJ1276试题代码
poj 2206 Magic Multiplying Machine.md
POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类POJ分类
poj2516代码最小费用最大流
poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题报告poj 解题...
poj 2827 Auto-Calculation Machine.md
北大POJ初级-图算法 解题报告+AC代码
POJ第1861题源码 POJ第1861题源码 POJ第1861题源码
poj分类poj分类poj分类poj分类
北大POJ1159-Palindrome 解题报告+AC代码
poj 3414解题报告poj 3414解题报告poj 3414解题报告poj 3414解题报告
C语言 poj npu 西工大 C语言Poj答案全完整打包,给有需要的朋友
poj 1012解题报告poj 1012解题报告poj 1012解题报告poj 1012解题报告
poj 2329解题报告poj 2329解题报告poj 2329解题报告poj 2329解题报告
poj 1659解题报告poj 1659解题报告poj 1659解题报告poj 1659解题报告
POJ1503解答 POJ1503解答,正确答案(已通过POJ)