您的位置:首页 > 编程语言 > C语言/C++

NYOJ 239 月老的难题

2013-04-17 08:44 218 查看


月老的难题

时间限制:1000 ms | 内存限制:65535 KB
难度:4

描述

月老准备给n个女孩与n个男孩牵红线,成就一对对美好的姻缘。

现在,由于一些原因,部分男孩与女孩可能结成幸福的一家,部分可能不会结成幸福的家庭。

现在已知哪些男孩与哪些女孩如果结婚的话,可以结成幸福的家庭,月老准备促成尽可能多的幸福家庭,请你帮他找出最多可能促成的幸福家庭数量吧。

假设男孩们分别编号为1~n,女孩们也分别编号为1~n。

输入第一行是一个整数T,表示测试数据的组数(1<=T<=400)

每组测试数据的第一行有两个整数n,K,其中男孩的人数与女孩的人数都是n。(n<=500,K<=10 000)

随后的K行,每行有两个整数i,j表示第i个男孩与第j个女孩有可能结成幸福的家庭。(1<=i,j<=n)
输出对每组测试数据,输出最多可能促成的幸福家庭数量
样例输入
1
3 4
1 1
1 3
2 2
3 2


样例输出
2


经典的匈牙利算法

算法不解释,主要讲一下优化

首先列出最经典的 易懂的代码

01.
#include
<algorithm>


02.
#include
<iostream>


03.
#include
<cstring>


04.
#include
<cstdlib>


05.
#include
<string>


06.
#include
<vector>


07.
#include
<cstdio>


08.
#include
<cmath>


09.
//#include
<map>


10.
#define
FLAG 0


11.
using
namespace
std;


12.
int
map[502][502];


13.
int
num,n;


14.


15.
int
vis[501];


16.
int
lin[501];


17.
inline
int
getnum(
int
i)


18.
{


19.
for
(
int
j=1;j<=n;j++)


20.
{


21.
if
(map[i][j]&&vis[j]==0)


22.
{


23.
vis[j]=1;


24.
if
(lin[j]==0||getnum(lin[j]))


25.
{


26.
lin[j]=i;


27.
return
1;


28.
}


29.
vis[j]=0;


30.
}


31.
}


32.
return
0;


33.
}


34.
int
main()


35.
{


36.
#if(FLAG)


37.
freopen
(
"in.txt"
,
"r"
,
stdin);


38.
//freopen("out.txt",
"w",stdout);


39.
#endif


40.
int
k,i,j,T,x,y;


41.
cin>>T;


42.
while
(T--)


43.
{


44.
num=0;


45.
memset
(lin,0,
sizeof
(lin));


46.
//cin>>n>>k;


47.
scanf
(
"%d%d"
,&n,&k);


48.
for
(i=1;i<=k;i++)


49.
{


50.
//cin>>x>>y;


51.
scanf
(
"%d%d"
,&x,&y);


52.
map[x][y]=1;


53.
}


54.
for
(i=1;i<=n;i++)


55.
{


56.
memset
(vis,0,
sizeof
(vis));


57.
if
(getnum(i))


58.
num++;


59.
}


60.
cout<<num<<endl;


61.
}


62.


66.
return
0;


67.
}


很可惜 超时了,需要各种优化,,,

01.
#include
<algorithm>


02.
#include
<iostream>


03.
#include
<cstring>


04.
#include
<cstdlib>


05.
#include
<string>


06.
#include
<queue>


07.
#include
<vector>


08.
#include
<cstdio>


09.
#include
<cmath>


10.
//#include
<map>


11.
#define
FLAG 0


12.
using
namespace
std;


13.
vector
<
int
>
map[502];
//用邻接表存储代替邻接矩阵,时间可缩短25倍:解释:500X500矩阵,也就是250000,


14.
//而最多有10000组有效数据(可能结成姻缘的连线)如果用邻接矩阵每次都要搜索250000次


15.
//
邻接表每次只搜索有用数据,就是100000组,所以时间大大缩短


16.
int
num,n;


17.


18.
bool
vis[501];


19.
int
lin[501];


20.
char
c;


21.
inline
int
readin()
//scanf的优化


22.
{


23.
c=
getchar
();


24.
while
(c<
'0'
||c>
'9'
)c=
getchar
();


25.
int
data=0;


26.
do
{


27.
data=data*10+c-
'0'
;c=
getchar
();


28.
}
while
(c<=
'9'
&&c>=
'0'
);


29.
return
data;


30.
}


31.
inline
int
getnum(
int
i)


32.
{


33.
for
(
int
j=0;j<map[i].size();j++)


34.
{


35.
if
(vis[map[i][j]]==0)


36.
{


37.
vis[map[i][j]]=1;


38.
if
(lin[map[i][j]]==0||getnum(lin[map[i][j]]))


39.
{


40.
lin[map[i][j]]=i;


41.
return
1;


42.
}


43.
//
vis[map[i][j]]=0;//若果加上这一句的话,NYOJ就会超时,按理说应该是省时间的,和理论不符,不懂,各种郁闷。。。


44.
}


45.
}


46.
return
0;


47.
}


48.
int
main()


49.
{


50.
#if(FLAG)


51.
freopen
(
"out111.txt"
,
"r"
,
stdin);


52.
freopen
(
"out.txt"
,
"w"
,
stdout);


53.
#endif


54.
int
k,i,j,T,x,y;


55.
cin>>T;


56.
while
(T--)


57.
{


58.
num=0;


59.
int
i=n+1;


60.
while
(i--)


61.
//
if(!map[i].empty())


62.
map[i].clear();


63.
memset
(lin,0,
sizeof
(lin));


64.
//cin>>n>>k;


65.
//scanf("%d%d",&n,&k);


66.
n=readin();


67.
k=readin();


68.
for
(i=1;i<=k;i++)


69.
{


70.
//cin>>x>>y;


71.
//
scanf("%d%d",&x,&y);


72.
x=readin();


73.
y=readin();


74.
map[x].push_back(y);


75.
}


76.
for
(i=1;i<=n;i++)


77.
{


78.
memset
(vis,0,
sizeof
(vis));


79.
if
(getnum(i))


80.
num++;


81.
}


82.
//
cout<<num<<endl;


83.
printf
(
"%d\n"
,num);


84.
}


85.


86.
return
0;


87.
}

下面是牛人的代码,时间超短

01.
#include<iostream>


02.
#include<cstdio>


03.
#include<cstring>


04.
#include<algorithm>


05.
using
namespace
std;


06.
#define
CLR(arr,val) memset(arr,val,sizeof(arr))


07.
inline
int
ReadInt()


08.
{


09.
char
ch
=
getchar
();


10.
int
data
= 0;


11.
while
(ch
<
'0'
||
ch >
'9'
)
ch =
getchar
();


12.
do
{data
= data*10 + ch-
'0'
;ch
=
getchar
();}
while
(ch
>=
'0'
&&
ch <=
'9'
);


13.
return
data;


14.
}


15.
const
int
MAX=510,MAX2=10010;


16.
int
Head[MAX];


17.
int
Next[MAX2];


18.
int
Num[MAX2],top=0;


19.
void
add(
int
u,
int
v)


20.
{


21.
Next[top]=Head[u];


22.
Num[top]=v;


23.
Head[u]=top++;


24.
}


25.
bool
used[MAX];


26.
int
linked[MAX];


27.
bool
Augument(
int
u)


28.
{


29.
for
(
int
i=Head[u];i!=-1;i=Next[i])


30.
{


31.
if
(!used[Num[i]])


32.
{


33.
used[Num[i]]=
true
;


34.
if
(linked[Num[i]]==-1
|| Augument(linked[Num[i]]))


35.
{


36.
linked[Num[i]]=u;


37.
return
true
;


38.
}


39.
}


40.
}


41.
return
false
;


42.
}


43.
int
main()


44.
{


45.
for
(
int
m=ReadInt();m--;)


46.
{


47.
int
n=ReadInt();


48.
CLR(Head,-1);


49.
CLR(linked,-1);


50.
top=0;


51.
for
(
int
i=ReadInt();i--;)


52.
add(ReadInt()-1,ReadInt()-1);


53.
int
cnt=0;


54.
for
(
int
i=0;i!=n;i++)
{ CLR(used,0);
if
(Augument(i))++cnt;}


55.
printf
(
"%d\n"
,cnt);


56.
}


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