您的位置:首页 > 其它

FZU - 2039 Pets(二分图匹配/匈牙利算法)

2016-05-04 21:03 459 查看
题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31898

代码:

暴力代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;

int n,m,q;

int main()
{
int t;
scanf("%d",&t);

for(int cas=1;cas<=t;cas++)
{

scanf("%d%d%d",&n,&m,&q);
int maps[105][105];
memset(maps,1,sizeof(maps));

/*for(int i=1;i<=100;i++)
{
for(int j=1;j<=100;j++)
maps[i][j]=1;
}*/
for(int i=0;i<q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
maps[x][y]=0;
}

int ans=0;

/*for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
printf("%d ",maps[i][j]);
}
printf("\n");
}*/

for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(maps[j][i]!=0)
{
ans++;
break;
}
}
}
//printf("%d %d %d",ans,m,n);
printf("Case %d: %d\n",cas,min(ans,min(m,n)));
}
}


暴力代码好像不对

虽然能AC。

3 3 4

2 1

2 3

3 1

3 3

匈牙利算法:

#include<stdio.h>
#include<string.h>

using namespace std;

int maps[1005][1005];
int vis[1005];
int n,m,q;
int marry[1005];

int judge(int u)
{
for(int i=1;i<=m;i++)
{
if(maps[u][i] || vis[i]==1)
continue;
vis[i]=1;

if(!marry[i]||judge(marry[i]))
{
marry[i]=u;
return 1;
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);

for(int cas=1;cas<=t;cas++)
{

scanf("%d%d%d",&n,&m,&q);

memset(maps,0,sizeof(maps));
memset(marry,0,sizeof(marry));

for(int i=0;i<q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
maps[x][y]=1;
}

int ans=0;

for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(judge(i))
ans++;
}

printf("Case %d: %d\n",cas,ans);
}
}


第二次自己打的代码:

#include<stdio.h>
#include<string.h>

using namespace std;

int maps[105][105];
int book[105];
int n,m,q;
int match[105];

int get(int x)
{
for(int i=1;i<=m;i++)                     //              从1到m
{
if(book[i]==0&&maps[x][i]==0)
{
book[i]=1;
if(match[i]==0||get(match[i]))
{
match[i]=x;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);

for(int i=1;i<=t;i++)
{
memset(maps,0,sizeof(maps));
memset(match,0,sizeof(match));

scanf("%d%d%d",&n,&m,&q);

for(int i=0;i<q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
maps[x][y]=1;
}

int ans=0;
for(int i=1;i<=n;i++)                       //    注意是从1到n   (顾客人数)
{
memset(book,0,sizeof(book));            //    每找到一条增广路配对数加一(见分析)
if(get(i))
ans++;<span style="white-space:pre">	</span>
}
printf("Case %d: %d\n",i,ans);
}
}


bool find(int x){
int i,j;
for (j=1;j<=m;j++){    //扫描每个妹子
if (line[x][j]==true && used[j]==false)
//如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了)
{
used[j]=1;
if (girl[j]==0 || find(girl[j])) {
//名花无主或者能腾出个位置来,这里使用递归
girl[j]=x;
return true;
}
}
}
return false;
}
/ \

| (这是个箭头)

数据(题意不同)(题意是男女配对找最大配对数-----------为3)

1 1

1 2

2 2

2 3

3 1

分析:

增广路是

若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径(举例来说,有A、B集合,增广路由A中一个点通向B中一个点,再由B中这个点通向A中一个点……交替进行)。

找到以1为起点的增广路,1-1;说明1可以配对,ans++;

找到以2为起点的增广路,2-2;说明2可以配对,ans++;

找到以3为起点的增广路,3-1;说明3可以配对,但在这时要想实现3的配对,需要更改 以1为起点的增广路,

因为在此之前1与1是配对的。

此时,一共有三条增广路,所以答案为3.

/*还有就是

1 1

2 1

时也会出现一条增广路。所以会出现 if ( book[ i ]==0 )book[ i ]=1;

这样就满足了。好像不对呀。不对。

是找2的增广路时,(find(2))

i=1;used【1】=1;find(girl【1】)

i=1;此时已经used【1】=1;

i=2;line【1】【2】=false;return 0;

i=2;return 0;即此时找不到以2为起点的增广路。

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: