二分图匹配
- 二分图:分为两个点集,左点集内部各点之间没有边,右点集同样
- 判断是否为二分图:染色法判断:
- 给一个点染色,给与它相连的点染另一个颜色,如果有冲突那就不是二分图
- 给一个点染色,给与它相连的点染另一个颜色,如果有冲突那就不是二分图
-
最大匹配
- 能够匹配最多顶点(每个顶点只能匹配一次)
-
完美匹配
- 所有顶点都能匹配,完美匹配就是最大匹配
-
最小顶点覆盖
- 用最少的顶点覆盖最多的边
- 最小顶点覆盖 = 最大匹配
-
最大独立集
- 两两之间没有边的顶点集合
- 最大独立集
= 所有顶点数 - 最小顶点覆盖
= 所有顶点数 - 最大匹配最大匹配:把边的利用最大化;每一条边的两个端点至少有一个能被匹配
独立集:点与点之间 不存在边,(如果有边肯定能匹配上)
1. 匈牙利算法
#include <bits/stdc++.h>
using namespace std;
int st[550][550];//邻接矩阵
int net[550],used[550];
int k,n,m;
int fin(int x)
{
for(int i=1;i<=m;i++)
{
if(st[x][i]&&!used[i])
{
used[i]=1;
if(net[i]==0||fin(net[i]))
{
net[i]=x;
return 1;
}
}
}
return 0;
}
int match()
{
int sum=0;
for(int i=1;i<=n;i++)
{
memset(used,0,sizeof(used));
if(fin(i)) sum++;
}
return sum;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>k&&k)
{
memset(st,0,sizeof(st));
memset(net,0,sizeof(net));
cin>>n>>m;
for(int i=1;i<=k;i++)
{
int x,y;
cin>>x>>y;
st[x][y]=1;
}
cout<<match()<<endl;
}
return 0;
}
2.染色体匹配 + 匈牙利算法
The Accomodation of Students: https://vjudge.net/problem/HDU-2444
题解
#include <bits/stdc++.h>
#include <vector>
using namespace std;
int n,m;
vector <int> st[205];
int color[205],used[205],net[205];
int judge(int x,int co)//染色
{
color[x]=co;
int t=st[x].size();
for(int i=0; i<t; i++)
{
int v=st[x][i];
if(color[v]==0&&judge(v,3-co))
return 1;
else if(color[v]!=3-co)
{
cout<<"No"<<endl;
return 1;
}
}
return 0;
}
int f2(int x)//匈牙利算法
{
int t=st[x].size();
for(int i=0; i<t; i++)
{
int v=st[x][i];
if(!used[v])
{
used[v]=1;
if(net[v]==0||f2(net[v]))
{
net[v]=x;
return 1;
}
}
}
return 0;
}
void solve()
{
int sum=0;
for(int i=1; i<=n; i++)
{
if(color[i]==0&&judge(i,1))
return ;
}
for(int i=1; i<=n; i++)
{
memset(used,0,sizeof(used));
if(f2(i)) sum++;
}
cout<<sum<<endl;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
for(int i=0; i<=205; i++)
st[i].clear();
memset(color,0,sizeof(color));
memset(net,0,sizeof(net));
for(int i=0; i<m; i++)
{
int x,y;
cin>>x>>y;
st[x].push_back(y);
}
solve();
}
return 0;
}
3
Cat VS Dog:https://vjudge.net/problem/HDU-3829
建立无向图 最大匹配结果需要除以2
#include <bits/stdc++.h>
#include <vector>
using namespace std;
pair <string,string> cd;
string x[520],y[520];
int st[550][550],vis[550],pre[550];
int n,m,p;
int sum=0;
void init()
{
sum=0;
memset(st,0,sizeof(st));
memset(pre,0,sizeof(pre));
}
int fin(int x)
{
for(int i=1; i<=p; i++)
{
if(st[x][i]&&vis[i]==0)
{
vis[i]=1;
if(pre[i]==0||fin(pre[i]))
{
pre[i]=x;
return 1;
}
}
}
return 0;
}
void solve()
{
for(int i=1; i<=p; i++)
{
memset(vis,0,sizeof(vis));
if(fin(i))sum++;
}
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m>>p)
{
init();
for(int i=1; i<=p; i++)
{
cin>>x[i]>>y[i];
for(int j=1; j<=i; j++)
{
if(x[i]==y[j]||y[i]==x[j])
st[i][j]=st[j][i]=1; //无向图
}
}
solve();
cout<<p-sum/2<<endl;
}
return 0;
}
4. Swap Free // Team Contest - 1
Swap Free:https://vjudge.net/contest/418417#problem/D
Swap Free:https://codeforces.com/gym/102423/problem/D
完整题目链接:https://codeforces.com/gym/102423/attachments/download/9792/2019-SER-D1-Problems.pdf
求最大独立集
Time limit: 1 second
A set of words is called swap free if there is no way to turn any word in the set into any other word in the set by swapping only a single pair of (not necessarily adjacent) letters.
You are given a set of 𝒏 words that are all anagrams of each other. There are no duplicate letters in any word. Find the size of the largest swap free subset of the given set. Note that it is possible for the largest swap free subset of the given set to be the set itself.
Input
The first line of input contains a single integer 𝒏 (1 ≤ 𝒏 ≤ 500).
Each of the next 𝒏 lines contains a single word 𝒘 (1 ≤ |𝒘| ≤ 26).
Every word contains only lower-case letters and no duplicate letters. All 𝒏 words are unique, and every
word is an anagram of every other word.
Output
Output a single integer, which is the size of the largest swap free subset.
Sample Input
6
abc
acb
cab
cba
bac
bca
Sample Output
3
Sample Input
11
alerts
alters
artels
estral
laster
ratels
salter
slater
staler
stelar
talers
Sample Output
8
Sample Input
6
ates
east
eats
etas
sate
teas
Sample Output
4
题意:找出集合中任意一个串交换两个字符不能变成另外一个串的 所有串的集合。
最大独立集
#include <bits/stdc++.h>
using namespace std;
string a[550];
//int st[550][550];
int vis[550],pre[550];
int n;
vector<int>st[555];
int fin(int x)
{
for(int i=0;i<st[x].size();i++)
{
int u=st[x][i];
if(vis[u]==0)
{
vis[u]=1;
if(pre[u]==0||fin(pre[u]))
{
// cout<<x<<" ---"<<u<<endl;
pre[u]=x;
return 1;
}
}
}
return 0;
}
int match()
{
int sum=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(fin(i)) sum++;
}
return sum;
}
int main()
{
ios::sync_with_stdio(false);
memset(pre,0,sizeof(pre));
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int num=0;
for(int li=0;li<a[i].size();li++)
{
if(a[i][li]!=a[j][li]) num++;
if(num>2) break;
}
if(num==2) st[i].push_back(j),st[j].push_back(i);
}
}
cout<<n-(match()/2)<<endl;
return 0;
}