您的位置:首页 > 其它

poj 3041二分匹配

2013-12-14 20:01 363 查看
题意:矩阵上有一些小行星,占据了一些格子,我们每次操作可以清理一列中的所有小行星,也可以清理一行中的所有小行星,问最少进行多少次操作可以清理掉所有的小行星。

分析:建图之后,会发现,题目意思就等于:最小覆盖点,

最小覆盖点 = 最大匹配;

问题就 = 求二分图的最大匹配数。

 

对于匈牙利算法有两种形式:

1、bfs  时间32ms

//32ms

#include
#include
using namespace std;

const int MAXN = 520;
int g[MAXN][MAXN], Mx[MAXN], My[MAXN], Nx,Ny;
int chk[MAXN], Q[MAXN], prev[MAXN];
int MaxMatch(void)
{
int res = 0;
int qs, qe;
memset(Mx, -1, sizeof(Mx));
memset(My, -1, sizeof(My));
memset(chk, -1, sizeof(chk));
for (int i = 1; i <= Nx; i++)
{
if (Mx[i] == -1)
{//对于x集合中的每个没有匹配的点i进行一次bfs找交错轨
qs = qe = 0;
Q[qe++] = i;
prev[i] = -1;

bool flag = 0;//判断是否找到
while (qs < qe && !flag)
{
int u = Q[qs];
for (int v = 1; v <= Nx && !flag; v++)
if (g[u][v]//如果u和v相连
&&chk[v] != i)//并且v没有被u check过
{
chk[v] = i;
Q[qe++] = My[v];//放进
if (My[v] >= 0)//如果v和其他的相连,则修改之
prev[My[v]] = u;
else
{//直到找到一个u和v都没有用过的
flag = 1;
int d = u, e = v;
while (d != -1)
{//确保回到最初
int t = Mx[d];
Mx[d] = e;
My[e] = d;
d = prev[d];
e = t;
}
}
}
qs++;
}
if (Mx[i] != -1)
res++;
}
}
return res;
}

int main()
{
cin>>Nx>>Ny;
memset(g , 0 ,sizeof(g));
int i , x , y;
for(i = 1 ; i <= Ny ;i++)
{
scanf("%d%d" , &x , &y);
g[x][y] = 1;

}
int sum = MaxMatch();
cout<<sum<<endl;
return 0;
}


 

2、dfs 时间 16ms

#include
#include
using namespace std;

const int MAX = 520 ;

int grap[MAX][MAX] , link[MAX] , useif[MAX] ;
int n , m;

int can(int t)
{
int i;
for(i = 1 ; i <= n ; i++)
{
if(grap[t][i] &&!useif[i])
{
useif[i] =1;
if(link[i] ==-1 || can(link[i]))
{
link[i]= t;
return1;
}
}
}
return 0;
}

int main()
{
scanf("%d %d" , &n , &m);
int i , x , y;
memset(grap , 0 , sizeof(grap));
for(i = 1 ; i <= m ; i++)
{
scanf("%d %d" , &x ,&y);
grap[x][y] = 1;
}
memset(link , -1 , sizeof(link));
int sum = 0;
for(i = 1 ; i <= n ; i++)
{
memset(useif , 0 ,sizeof(useif));
if(can(i))
sum +=1;
}
printf("%d\n" , sum);
return 0;
}  //16ms


 

本来两种形式算法的效率的差不多的,但在这个题目中相差一倍,可能是测试数据的原因。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: