二分图匹配,头痛难题

Heister 2010-03-16 05:08:27
如题, 如果 有左半图和右半图, 可以理解为 左边图是用户 右半图是会议
只有一个用户申请了这个会议才能够匹配,如果没申请则不能匹配, 请问这样带匹配条件的图怎么样才能找到最大匹配数量?
如果同时左边的用户还带有优先级,优先级高的优先获得匹配又该怎么匹配呢?
...全文
537 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Heister 2010-03-19
  • 打赏
  • 举报
回复
哈哈, 多谢了, 听你一解释才发现原来是这样的,好久没搞这些东西都不记得了, 那我现在就是在查询 增广路径的时候优先匹配 优先级高的用户, 直到找不到路径时 应该就是最佳匹配了, 并且 优先级高的用户一定会获得匹配(如果存在匹配)
diablox0147 2010-03-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 heister 的回复:]
我只是想知道, 对于一个图, 如果左图到右图的一条连接线 是有条件的, 能不能用求二分图最大流的方法来解

比如左图是用户,右图是会议, 只有用户选择了一个会议才能连接起来, 如果没选就不能连接, 而且用户可以申请多个会议,但是安排时只能安排一个. 现在要求尽可能多的安排会议 ,而且 优先级高的用户一定要先得到分配

这样的图能用二分图最大流的方法来解吗,我感觉应该是可以的
[/Quote]

当然可以,用户选了n个会议就是n条线,如果没选就是独立的点。
优先级高的只需要放到最先匹配就一定能够获得会议
diablox0147 2010-03-18
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 heister 的回复:]
引用 9 楼 diablox0147 的回复:
引用 8 楼 heister 的回复:
我只是想知道, 对于一个图, 如果左图到右图的一条连接线 是有条件的, 能不能用求二分图最大流的方法来解

比如左图是用户,右图是会议, 只有用户选择了一个会议才能连接起来, 如果没选就不能连接, 而且用户可以申请多个会议,但是安排时只能安排一个. 现在要求尽可能多的安排会议 ,而且 优先级高的用户一定……
[/Quote]

这个不用担心,只要匹配过一次的顶点之后它之后绝对不会被取消匹配,最多就是换掉了和它匹配的会议而已。

就像我上面代码里解释的最后一句:
//就像是原本有几个人做板凳上,然后突然来了个人,叫大家让出个位置,把某人原本做的地方让给刚来的人.

虽然坐凳子上的人移了位置,但是他们一直都坐(匹配)在上面.

只要稍微模拟下就可以知道了,每次都是从未匹配的用户开始到未匹配会议,,这个非常重要。也就是说虽然在这次匹配中虽然会改变个别用户的匹配但是不会取消他们的匹配。文字表达比较困难,比如
有1和2这2个用户和3,4这2个会议。

首先假设,1和3有匹配:
1-3
2 4

然后开始匹配二号,二号寻找路径应该会经过这样:2-3-1-4这样经过4个顶点3条路径。
然后开始更新左边的顶点,首先是1号,在这次路径里是和4配对,所以把1号的顶点换到了4上,然后把本来和1配对的3号给了2号。

这不就是像:
原本有几个人做板凳上,然后突然来了个人,叫大家让出个位置,把某人原本做的地方让给刚来的人.
qiuzhenguang 2010-03-18
  • 打赏
  • 举报
回复
学习。匈牙利算法解决二分图是很经典的。
Heister 2010-03-18
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 diablox0147 的回复:]
引用 8 楼 heister 的回复:
我只是想知道, 对于一个图, 如果左图到右图的一条连接线 是有条件的, 能不能用求二分图最大流的方法来解

比如左图是用户,右图是会议, 只有用户选择了一个会议才能连接起来, 如果没选就不能连接, 而且用户可以申请多个会议,但是安排时只能安排一个. 现在要求尽可能多的安排会议 ,而且 优先级高的用户一定要先得到分配

这样的图能用二分图最大流的方法……
[/Quote]

多谢diablox0147了,你的回复对我有很大的帮助

现在的问题是,如果优先级高的用户一定要获得匹配的话, 代码要怎么写? 因为如果优先级高的要先获得匹配的话, 那么在找到增广路径时, 原来的 路径是可能会被被删除的, 所以得到的结果可能是优先级最高的用户反而没有获得匹配(被删了), 也许我理解错了, 现在还不知道算法到底是要怎么写?
hua_zhixing_ 2010-03-17
  • 打赏
  • 举报
回复
第一个问题,可匈牙利算法(自己去网上查吧);
第二个问题,我觉得,先将用户按优先级排序,然后再逐个匹配。
Heister 2010-03-17
  • 打赏
  • 举报
回复
我只是想知道, 对于一个图, 如果左图到右图的一条连接线 是有条件的, 能不能用求二分图最大流的方法来解

比如左图是用户,右图是会议, 只有用户选择了一个会议才能连接起来, 如果没选就不能连接, 而且用户可以申请多个会议,但是安排时只能安排一个. 现在要求尽可能多的安排会议 ,而且 优先级高的用户一定要先得到分配

这样的图能用二分图最大流的方法来解吗,我感觉应该是可以的
LeonTown 2010-03-17
  • 打赏
  • 举报
回复
mark
diablox0147 2010-03-17
  • 打赏
  • 举报
回复
正好刚写了个最大匹配的,带解释,至于优先级,只需要把优先级最高的放最前面最先匹配就可以了


#include <iostream>
#define N 6
#define L 3
#define R 3
using namespace std;
bool RToL(int);


int map[N][N] = {{0,0,0,1,1,1},
{0,0,0,0,0,1},
{0,0,0,0,0,1},
{0,0,0,0,0,0},
{0,0,0,0,0,0},
{0,0,0,0,0,0}};

int lien[N] = {-1};
int matched[N] = {0};

bool LToR(int curPoint)//左边的点找右边可以连接的点
{
for(int i=L; i<N; i++)//对每个右边的点
{
if(map[curPoint][i] && lien[i] == -1)//如果未进入链里
{
lien[curPoint] = i;//这个点连接到右边的点i号
if(RToL(i))//如果找到了增广链
return true;
else//如果没找到,那就试下下个链路
{
lien[curPoint] = -1;
continue;
}
}
}
return false;
}

bool RToL(int curPoint)
{
for(int i=0; i<L; i++)//对每个左边的点
{
if(map[i][curPoint] && lien[i] == -1)
{
lien[curPoint] = i;
if(LToR(i))
return true;
else
{
lien[curPoint] = -1;
continue;
}
}
}
//右边寻找的话是有特殊情况的,那就是如果没找到接下去的点的
//而右边的点本身没匹配过那么就说明这条增广链到次为止
for(int i=0; i<L; i++)
if(matched[i] == curPoint+1)
return false;
return true;
}

//唉,其实二分图最大匹配很简单,网络上好多都搞的很麻烦,结果我也迷糊了一镇,
//说什么要有奇数条边,而且选好后要对边进行"异或"操作把新链里的奇数边加进去偶数边拿出来阿啥啥的
//搞得人比较混乱,让人把注意力放到边上面。。。实际上根本不需要注意什么边,只需注意顶点就可以了
//首先从左边的未配对的顶点开始,一个个试过来,如果找到一条链,那根本不用管找到的链是奇数还是偶数,
//只需注意找到的增广链的头和尾都必须是未配对的就够了,然后对这条增广链里所有左边的顶点进行刷新,
//就是在这条增广链里不管左边的顶点是否配对过,都把它们的配对改成这条增广链里找到的相对应的右边的点
//然后继续找下条增广链直到试过所有左边的点就可以了,右边的点只在找增广链的时候有用,其他时候不用管
//---------------------------------
//解释:不过为什么这样就可以了呢? 其实就是把网络上的方法简化了,本来所谓的找到奇数边然后偶数边去掉奇数边加进去
//的意思就是只对左边的顶点进行更新,把左边的顶点可能已经配对过的点交换下它们的配对而已,比如有左3右3个图:
//本来有1配5,2配6.这时候点3和点4未配对,然后如果点3经过3-6-2-5-1-4,
//然后如果对所有左边的点更新,根据路径将变成:3配6,2配5,1配4。。。。。
//仔细看看,不就是把左边点1和点2原本的配对"往上抬"了下么。然后原本和点2配对的点6会空出来。正好留给点3
//而且只要起点和终点都是为配对的点就可以保证不会出现重复配对的情况
//就像是原本有几个人做板凳上,然后突然来了个人,叫大家让出个位置,把某人原本做的地方让给刚来的人.
void match()
{
for(int i=0; i<L; i++)
{
memset(lien, -1, sizeof(lien));
if(matched[i]==0)//左边的开始节点必须为未配对的
if(LToR(i))//寻找
{
for(int g=0; g<L; g++)//只对每个左边的点查看
{
if(lien[g]!=-1 && matched[lien[g]] == 0)//如果左边的点有连接
{
matched[matched[g]-1] = 0;//把原本右边可能已经配对的去掉配对
matched[g] = lien[g]+1;//然后从新连接左边到右边
matched[lien[g]] = g+1;//然后把右边的连接到左边
}
}
}
}
for(int i=0; i<N; i++)
cout<<"第"<<i+1<<"号顶点配:"<<matched[i]<<"号顶点 "<<endl;
}

int main()
{
match();
return 0;
}
绿色夹克衫 2010-03-16
  • 打赏
  • 举报
回复
发生冲突时,优先级高的人优先获得匹配

如果是这样的话,直接用贪心就可以了,先找最高优先级的用户,对应的教室,再找其次的,以此类推。

但这样排出来的结果,恐怕会造成很多资源的浪费,更好的方法就是转化为二分图,
并且应该正好可以用最大流来做,求二分图的最大匹配。
假设有一个公共的源S,连接到所有用户,而用户到教室的权值不同,而所有的教室都通向一个共同的汇T。
求S到T的最大流,应该就差不多,这样的话求出的解,要比完全依照用户优先级得出的结果更有效。

[Quote=引用 2 楼 heister 的回复:]

这个题目不一定能用 二分图来解, 只是想问问看行不行

题目是 用户申请 参加会议, 一个会议只能 一个人参加, 每个用户都有自己的优先级, 一个用户能申请参加多个会议, 发生冲突时,优先级高的人优先获得匹配, 而且不能匹配用户到一个他没有申请的会议, 这种问题能用 二分图来解吗? 如果不行,有什么其他算法可以?
[/Quote]
Heister 2010-03-16
  • 打赏
  • 举报
回复
这个题目不一定能用 二分图来解, 只是想问问看行不行

题目是 用户申请 参加会议, 一个会议只能 一个人参加, 每个用户都有自己的优先级, 一个用户能申请参加多个会议, 发生冲突时,优先级高的人优先获得匹配, 而且不能匹配用户到一个他没有申请的会议, 这种问题能用 二分图来解吗? 如果不行,有什么其他算法可以?
绿色夹克衫 2010-03-16
  • 打赏
  • 举报
回复
二分图的问题一般可以用最大流来解,题目不是很明白。

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧