uva12083(二分图最大独立集)

来源:互联网 发布:hp网络交换机 编辑:程序博客网 时间:2024/06/05 00:26

https://vjudge.net/problem/UVA-12083(uva12083 点击打开链接)

思路:二分图的最大独立集(二分图中任选两点之间,都不会有边相连)。

分析:首先,二分图肯定不能有边将同一侧的点相连。他们只要满足四个条件中的一个就不会产生爱意,相反,如果四个条件都不满足,就会产生爱意。每个人要么男,要么女,这样同侧就肯定不会有边相连,然后左右两边建边。如果其他三个条件都不满足,就建一条无向边。所以这个问题就变成了选择尽量多的点,满足任意一条边的两个点都不能同时被选到。这就是最大独立集。

那么怎么解这个最大独立集?其实它是和最小点覆盖互补的。互补就是指,数目是总点数减最小覆盖,解集只要把最小覆盖里的“已选点”和“未选点”互换即可。
为什么是互补?看两者的定义是什么。
(1)最小覆盖集:对于每条边,至少有一个点被选中。
(2)最大独立集:对于每条边,至少有一个点不被选中。
每个最小覆盖集都和一个唯一的最大独立集互补,每个最大独立集也都和一个唯一的最小覆盖集互补。
所以,综上:
最大独立集:选择尽量多的点,满足任意一条边的两个端点不被同时选中。
解集:与最小覆盖集互补。最大独立集点数 = 总点数 - 最小覆盖集点数 = 总点数 - 最大匹配数。

代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <cstdlib>using namespace std;const int maxn = 500 + 10;struct node{    int height;    char sex;    string music;    string sport;}person[maxn];int t;int line[maxn];bool used[maxn];bool judge(const node a,const node b){    if(abs(a.height - b.height) <= 40 && a.sex != b.sex && a.music == b.music && a.sport != b.sport)            return true;        return false;}//板子:bool dfs(int x){//右边的点    for(int i = 1;i <= t;i++)    {        if(i != x && used[i] == false)        {            if(judge(person[i],person[x]))            {                used[i] = 1;                if(line[i] == 0 || dfs(line[i]))                {                    line[i] = x;                    return true;                }            }        }    }    return false;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d",&t);        for(int i = 1;i <= t;i++)        {            cin >> person[i].height >> person[i].sex;            cin >> person[i].music >> person[i].sport;        }        memset(line,0,sizeof(line));        int ans = 0;        for(int i = 1;i <= t;i++)//左边的点        {            memset(used,0,sizeof(used));            if(dfs(i))                ans++;        }        printf("%d\n",t - ans/2);    }}

模板:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N=1001;int n1,n2,k;//n1,n2为二分图的顶点集,其中x∈n1,y∈n2int map[N][N],vis[N],link[N];//link记录n2中的点y在n1中所匹配的x点的编号int find(int x){    int i;    for(i=1;i<=n2;i++)    {        if(map[x][i]&&!vis[i])//x->i有边,且节点i未被搜索        {            vis[i]=1;//标记节点已被搜索            //如果i不属于前一个匹配M或被i匹配到的节点可以寻找到增广路            if(link[i]==0||find(link[i]))            {                link[i]=x;//更新                return 1;//匹配成功            }        }            }    return 0;}int main(){    int i,x,y,s=0;    scanf("%d%d%d",&n1,&n2,&k);    for(i=0;i<k;i++)    {        scanf("%d%d",&x,&y);        map[x][y]=1;    }    for(i=1;i<=n1;i++)    {        memset(vis,0,sizeof(vis));        if(find(i))            s++;    }    printf("%d\n",s);    return 0;}
  • 总算明白了点儿,明天再看看几者的关系吧,困了。。。