匈牙利算法
来源:互联网 发布:qq飞车指挥官全29数据 编辑:程序博客网 时间:2024/05/20 16:35
参考博客:http://blog.csdn.net/dark_scope/article/details/8880547(博主写的很详细)
在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(-_-||暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在让我们无视掉所有的单相思(好忧伤的感觉),你拥有的大概就是下面这样一张关系图,每一条连线都表示互有好感。
本着救人一命,胜造七级浮屠的原则,你想要尽可能地撮合更多的情侣,匈牙利算法的工作模式会教你这样做:
===============================================================================
一: 先试着给1号男生找妹子,发现第一个和他相连的1号女生还名花无主,got it,连上一条蓝线
===============================================================================
二:接着给2号男生找妹子,发现第一个和他相连的2号女生名花无主,got it
===============================================================================
三:接下来是3号男生,很遗憾1号女生已经有主了,怎么办呢?
我们试着给之前1号女生匹配的男生(也就是1号男生)另外分配一个妹子。
(黄色表示这条边被临时拆掉)
与1号男生相连的第二个女生是2号女生,但是2号女生也有主了,怎么办呢?我们再试着给2号女生的原配()重新找个妹子(注意这个步骤和上面是一样的,这是一个递归的过程)
此时发现2号男生还能找到3号女生,那么之前的问题迎刃而解了,回溯回去
2号男生可以找3号妹子~~~ 1号男生可以找2号妹子了~~~ 3号男生可以找1号妹子
所以第三步最后的结果就是:
===============================================================================
四: 接下来是4号男生,很遗憾,按照第三步的节奏我们没法给4号男生腾出来一个妹子,我们实在是无能为力了……香吉士同学走好。
(以上为借鉴)。代码如下int match[maxn],n;//match表示谁与谁匹配
bool used[maxn],link[maxn][maxn];//used表示是否尝试给变过他的属性,及在find中是否扫过他,如果已经扫过了说明他已经用了。link表示关系。***used每次都要更新
int find(int a){
for(int i=0;i<n;i++){
if(link[a][i]&&!used[i])
{
used[i]=1;
if(match[i]==-1||find(match[i]))
{
match[i]=a;
return 1;
}
}
}
return 0;
}
int hungary(){
int ans=0;
memset(match,-1,sizeof(match));
for(int i=0;i<n;i++)
{
memset(used,0,sizeof(used));********
ans+=find(i);
}
return ans;
}
例题:hdu 1068
题意 有一群人,有些人彼此之间有好感,现在老师要挑出一群人,并且彼此之间没有好感
就是求最大独立集
由于是一般图,所以要把每一个点分成两个p1与p2,p1表示从 p出去的边,p2表示进入p的边,若此可以当作二分,所以求出的最大匹配是真是值得二倍
所以结果就是n-ans/2;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1000;
int match[maxn],n;
bool used[maxn],link[maxn][maxn];
int find(int a){
for(int i=0;i<n;i++){
if(link[a][i]&&!used[i])
{
used[i]=1;
if(match[i]==-1||find(match[i]))
{
match[i]=a;
return 1;
}
}
}
return 0;
}
int hungary(){
int ans=0;
memset(match,-1,sizeof(match));
for(int i=0;i<n;i++)
{
memset(used,0,sizeof(used));
ans+=find(i);
}
return ans;
}
int main()
{
int num,a,b;
while(~scanf("%d",&n)){
memset(link,0,sizeof(link));
for(int i=0;i<n;i++){
scanf("%d: (%d)",&a,&num);
for(int j=0;j<num;j++)
{
scanf("%d",&b);
link[a][b]=1;
}
}
int ans=hungary();
printf("%d\n",n-ans/2);
}
return 0;
}
hdu 4185
题意:给你一个图每件物品会占用连着的两个#问你可以放多少个物品
题解:通过把#抽象出来就是给#一个编号如果有连着的两个#就把他们连起来,求最大匹配就可以了,因为是无向图,边都加了两次,所以得出的最大匹配要除以2.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=605;
const int M=6005;
int len,pos[N][N];
int dir[4][2]={0,1,0,-1,-1,0,1,0},link[N];
bool used[N];
char str[N][N];
vector< int >edge[M];
int find(int k){
for(int i=0;i<edge[k].size();i++){
int v=edge[k][i];
if(!used[v]){
used[v]=1;
if(link[v]==-1||find(link[v])){
link[v]=k;
return 1;
}
}
}
return 0;
}
int hungry(int n){
int ans=0;
memset(link,-1,sizeof(link));
for(int i=0;i<n;i++){
memset(used,0,sizeof(used));
ans+=find(i);
}
return ans;
}
int main()
{
int n,t,T;
t=1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
len=0;
for(int i=0;i<n;i++){
scanf("%s",str[i]);
for(int j=0;j<n;j++){
if(str[i][j]=='#')
{
pos[i][j]=len++;
}
}
}
for(int i=0;i<M;i++)
{
edge[i].clear();
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int x,y,u,v;
if(str[i][j]=='.')continue;
u=pos[i][j];
for(int k=0;k<4;k++){
x=dir[k][0]+i;
y=dir[k][1]+j;
if(x>=0&&x<n&&y>=0&&y<n&&str[x][y]=='#'){
v=pos[x][y];
edge[u].push_back(v);
edge[v].push_back(u);
}
}
}
}
int ans=hungry(len);
printf("Case %d: %d\n",t++,ans/2);
}
return 0;
}
- 匈牙利算法
- 匈牙利算法!!!
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- 匈牙利算法
- JAVA工程师个人职业规划
- Android Jackson、Gson、FastJson解析框架对比
- 生成二维码
- Sitemesh 3 的使用及配置
- ButterKnife 8.0.1不生效的问题
- 匈牙利算法
- 10天精通Sass 之 Sass列表函数
- ubuntu14.04LTS安装maven和eclipse的maven插件
- HTML 5新标签及含义总结
- 跟我一起写操作系统(一)——10分钟写个操作系统
- CSS中的display:inline-block
- 数据结构实验之查找一:二叉排序树
- c# byte[] 与string转化
- Nginx服务器配置文件nginx.conf实例详解