题目: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为起点的增广路。
*/