您的位置:首页 > 其它

POJ 3020 / POJ 3041 关于二分图最大匹配的一些变形

2013-12-31 21:05 531 查看
其实这两个题早就过了,本想着等看完KM算法一块发的,可是最近一直在忙考试和CF,迟迟没写出来,感觉再拖下去这两个就要忘了,所以还是先发出来吧。

POJ 3020 二分图的最小顶点覆盖 等于 最大匹配

定义:设K为G的一部分的点的集合,若图G中的每一条边至少有一个顶点在K中,则称K为G的一点顶点覆盖。

    若G中不存在满足|K'| < |K|的点覆盖K' 则称K为G的最小点集覆盖。

设G为二分图,M为G的最大匹配,S为最小顶点覆盖的点集。

因为匹配M中的边两两没有交点,所以覆盖这M条边至少需要M个点。

若G中仍然存在两端都不为匹配点的边,则存在一条增广路,与M为最大匹配相矛盾。

对于一对匹配点,选择其中一个加入S时,若存在一条边未被覆盖,则将该点删除,加入另一点。

若两种情况均存在一天未被覆盖的边则说明崔在一条增广路,与M为最大匹配相矛盾。

故肯定存在一种选择方案使得在M对匹配点中选择M个点,使得所有的边均被覆盖,又因为覆盖M条

匹配边至少需要M个点,所以|s| == M。

POJ 3041  最大独立点集 等于 点的个数减去最大匹配

定义:设K为G的一部分的点的集合,若K中任意两点均不相邻,则称K为G的一个独立点集。

    若G中不存在满足|K'| > |K|的独立点集K',则称K为G的最大独立点集。

在一个图中,独立集和顶点覆盖有互补的性质。

T是G的独立点集  <=>  G中每条边至少有一个顶点在V(G) - T 中 <=> V(G) - T是G的一个顶点覆盖

而在二分图中最小点集覆盖等于最大二分匹配,所以最大独立点集等于点的个数减去最大匹配。

上述证明完全是自己瞎作的,不当之处,望不吝赐教。

下面说一下这两个题的思路:

其实两个题难度差不许多,基本属于拿来测代码的。

POJ 3041 可以将给出的点看成边,X,Y轴上的整数坐标位置看成点,则就抽象出了二分图,剩下的问题就迎刃而解了。

POJ 3020  给出的点作为点,两个相邻的点之间加一条边,因为不存在奇环,所以必为二分图。

POJ 3020

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>

#pragma comment(linker, "/STACK:1024000000");
#define LL unsigned long long int

using namespace std;

struct N
{
int v;
N *next;
}*head[410];

N *creat()
{
N *p = (N*)malloc(sizeof(N));
p->next = NULL;
return p;
};

int point[41][11];

char s[41][11];

int jx[] = {-1, 0, 1, 0};
int jy[] = { 0,-1, 0, 1};

int Matching_Point[410];
bool mark[410];

bool dfs(int s)
{
for(N *p = head[s]->next; p != NULL; p = p->next)
{
if(mark[p->v] == false)
{
mark[p->v] = true;
if(Matching_Point[p->v] == -1 || dfs(Matching_Point[p->v]))
{
Matching_Point[p->v] = s;
Matching_Point[s] = p->v;
return true;
}
}
}
return false;
}

int Cal_Maximal_Matching(int n)
{
memset(Matching_Point,-1,sizeof(Matching_Point));

int i,ans = 0;

for(i = 1; i < n; ++i)
{
if(Matching_Point[i] == -1)
{
memset(mark,false,sizeof(mark));
if(dfs(i))
{
ans++;
}
}
}
return ans;
}

int main()
{
int T,n,m,i,j,k,top,x,y;
N *p;

for(i = 0; i < 401; ++i)
{
head[i] = creat();
}

scanf("%d",&T);

while(T--)
{
scanf("%d %d",&n,&m);

for(i = 0; i <= n*m; ++i)
{
head[i]->next = NULL;
}

for(i = 0; i < n; ++i)
{
scanf("%*c%s",s[i]);
}

top = 1;
memset(point,-1,sizeof(point));

for(i = 0; i < n; ++i)
{
for(j = 0; j < m; ++j)
{
if(s[i][j] == '*')
{
point[i][j] = top++;
}
}
}

for(i = 0; i < n; ++i)
{
for(j = 0; j < m; ++j)
{
if(point[i][j] != -1)
{
for(k = 0; k < 4; ++k)
{
x = i+jx[k];
y = j+jy[k];
if(0 <= x && x < n && 0 <= y && y < m && point[x][y] != -1)
{

p = creat();
p->v = point[x][y];
p->next = head[point[i][j]]->next;
head[point[i][j]]->next = p;
}
}
}
}
}
printf("%d\n",top-1-Cal_Maximal_Matching(top));
}
return 0 ;
}


POJ  3041

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>

#pragma comment(linker, "/STACK:1024000000");
#define LL long long int

using namespace std;

const int MAXN = 1010;

struct N
{
int v;
N *next;
}*head[MAXN];

N *creat()
{
N *p = (N *)malloc(sizeof(N));
p->next = NULL;
return p;
}

bool mark[MAXN];

int color[MAXN];

int Match_Point[MAXN];

bool dfs(int t)
{
for(N *p = head[t]->next; p != NULL; p = p->next)
{
if(mark[p->v] == false)
{
mark[p->v] = true;
if(Match_Point[p->v] == -1 || dfs(Match_Point[p->v]))
{
Match_Point[p->v] = t;
Match_Point[t] = p->v;
return true;
}
}
}
return false;
}

bool bfs(int n)
{
queue<int> q;
int s,i;
N *p;

for(i = 1;i <= n; ++i)
{
if(color[i] == -1)
{

q.push(i);
color[i] = 0;

while(q.empty() == false)
{
s = q.front();
q.pop();

for(p = head[s]->next; p != NULL; p = p->next)
{
if(color[p->v] == -1)
{
color[p->v] = (color[s] == 1 ? 0 : 1);
q.push(p->v);
}
else if(color[p->v] == color[s])
{
return true;
}
}
}
}
}

return false;
}

int Cal_Maximal_Matching(int n)
{
int i,ans = 0;

memset(Match_Point,-1,sizeof(Match_Point));

for(i = 1;i <= n; ++i)
{
if(Match_Point[i] == -1)
{
memset(mark,false,sizeof(mark));
if(dfs(i))
ans++;
}
}
return ans;
}

int main()
{
int i,n,m,u,v;
N *p;

for(i = 0;i <= MAXN*2; ++i)
{
head[i] = creat();
}

while(scanf("%d %d",&n,&m) != EOF)
{
for(i = 1;i <= n; ++i)
{
head[i]->next = NULL;
}

while(m--)
{
scanf("%d %d",&u,&v);
v += n;
p = creat();
p->v = v;
p->next = head[u]->next;
head[u]->next = p;
p = creat();
p->v = u;
p->next = head[v]->next;
head[v]->next = p;
}

printf("%d\n",Cal_Maximal_Matching(n*2));

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