poj3041

用c语言写的,memset不用包含头文件

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

分析:一个小行星,要么清理该行,要么该列。所以也就是每个小行星对应的行列中至少选择一样来清理。下面建图,如果我们把每行看成集合一中的点,每列看成集合二中的点,一个小行星看成是其对应行列的连线,那么也就是说不能存在某一条连线两边的点都没有被选中的情况。这恰好就是二分图最小点集覆盖的要求。

 

 

最小点集覆盖==最大匹配。在这里解释一下原因。

 

首先,最小点集覆盖一定>=最大匹配,因为假设最大匹配为n,那么我们就得到了n条互不相邻的边,光覆盖这些边就要用到n个点。

 

现在我们来思考为什么最小点击覆盖一定<=最大匹配。

任何一种n个点的最小点集覆盖,一定可以转化成一个n的最大匹配。因为最小点集覆盖中的每个点都能找到至少一条只有一个端点在点集中的边。

如果找不到则说明该点所有的边的另外一个端点都被覆盖,所以该点则没必要被覆盖,和它在最小点集覆盖中相矛盾。

多个覆盖点都只能选则同一个点组成匹配的情况是不会出现的。因为如果出现这种情况的话,那么这几个点一定不是最小点集覆盖。因为这几个点(设为点集合S)既然只有一个点A可以组成匹配,说明这些S中的点除去与点A的边之外的其他边的另一端都是覆盖点,即S中点的其他边都已被其他点覆盖到,S里点被选为覆盖集是要覆盖S与A连接的那条边,所以最小点集覆盖应该选那个点A即可覆盖这些边,而不选S中的点。

只要每个端点都选择一个这样的边,就必然能转化为一个匹配数与点集覆盖的点数相等的匹配方案。所以最大匹配至少为最小点集覆盖数,即最小点集覆盖一定<=最大匹配。

 

综上,二者相等。

View Code
#include <stdio.h>

#define maxn 501

struct Edge
{
int v;
};

int n, k, map[maxn][maxn];
int vis[maxn], connect[maxn];

void input()
{
int i;
for (i =0; i < k; i++)
{
int a, b;
scanf(
"%d%d", &a, &b);
a
--;
b
--;
map[a][b]
=1;
}
}

int work(int a)
{
int i;
for (i =0; i < n; i++)
if (map[a][i] &&!vis[i])
{
vis[i]
=1;
if (connect[i] ==-1|| work(connect[i]))
{
connect[i]
= a;
return1;
}
}
return0;
}

int main()
{
//freopen("D:\\t.txt", "r", stdin);
scanf("%d%d", &n, &k);
input();
int i;
memset(connect,
-1, sizeof(connect));
for (i =0; i < n; i++)
{
memset(vis,
0, sizeof(vis));
work(i);
}
int ans =0;
for (i =0; i < n; i++)
if (connect[i] !=-1)
ans
++;
printf(
"%d", ans);
return0;
}
posted @ 2011-03-03 09:17 金海峰 阅读(...) 评论(...) 编辑 收藏