【UVA12083】Guardian of Decency

来源:互联网 发布:龚琳娜 知乎 编辑:程序博客网 时间:2024/06/05 08:08

题意

  有N个人,每个人有四个属性:WSexMuSp
  两个人uv不能出现在同一个集合当且仅当满足:
  |WuWv|40SexuSexv
  Muu=MuvSpuSpv
  问最多可以选出多少人使得这些人在同一个集合
  N500,最多100组数据

解法

二分图最大匹配:
  这道题有两种思考方向:
  ①.不排斥的人之间连边,那么问题转化为求最大团,很麻烦,不作考虑
  ②.排斥的人之间连边,那么问题转化为求最大独立集,比较简单,所以我们采取此种方法
  最大独立集一般只有树的最大独立集和二分图的最大独立集两种,本题显然不可能是树,于是考虑怎么构建二分图
  很明显,因为Sex属性只有两种(不是男,就是女),所以可以按照Sex将图分为两个部分,然后再根据另外三个条件进行连边(本题的N比较小,所以使用矩阵方便一些)
  然后就是要求最大独立集了,这里有一个结论:二分图的最大独立集=总点数-最小覆盖数,二分图的最小覆盖数=最大匹配
  (证明请看博客:http://blog.csdn.net/techmonster/article/details/50011363)
  所以使用匈牙利算法求出最大匹配即可

复杂度

O(TN|E|

代码

#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<map>#define Rint register int#define Lint long long intusing namespace std;const int INF=0x3f3f3f3f;const int E=100010;const int N=510;bool g[N][N],vis[N],sex[N];int match[N],w[N];int mu[N],cntm;int sp[N],cnts;int T,n,cnt;map<string,int> f,v;int abs(Rint x){    return x<0 ? -x : x ;}bool find(Rint k){    for(Rint i=1;i<=n;i++)        if( !vis[i] && g[k][i] )        {            vis[i]=1;            if( !match[i] || find( match[i] ) )            {                match[i]=k;return true ;            }        }    return false ;}int main(){    char cs,a[N],b[N];    scanf("%d",&T);    while( T-- )    {        cnt=cntm=cnts=0;        f.clear(),v.clear();        scanf("%d",&n);        for(Rint i=1;i<=n;i++)        {            scanf("%d %c%s%s",&w[i],&cs,a,b);            if( !f[a] )   f[a]=++cntm;            if( !v[b] )   v[b]=++cnts;            mu[i]=f[a],sp[i]=v[b];            sex[i]=(cs=='M');            match[i]=0;        }        for(Rint i=1;i<=n;i++)            for(Rint j=i+1;j<=n;j++)                if( sex[i]==sex[j] || abs( w[i]-w[j] )>40 || mu[i]!=mu[j] || sp[i]==sp[j] )   g[i][j]=g[j][i]=0;                else   g[i][j]=g[j][i]=1;        for(Rint i=1;i<=n;i++)        {            for(Rint j=1;j<=n;j++)   vis[j]=0;            if( find( i ) )   cnt++;        }        printf("%d\n",n-cnt/2);    }    return 0;}
原创粉丝点击