Cat VS Dog 最大独立集

The zoo have N cats and M dogs, today there are P children visiting the zoo, each child has a like-animal and a dislike-animal, if the child’s like-animal is a cat, then his/hers dislike-animal must be a dog, and vice versa.
Now the zoo administrator is removing some animals, if one child’s like-animal is not removed and his/hers dislike-animal is removed, he/she will be happy. So the administrator wants to know which animals he should remove to make maximum number of happy children.

Input
The input file contains multiple test cases, for each case, the first line contains three integers N <= 100, M <= 100 and P <= 500.
Next P lines, each line contains a child’s like-animal and dislike-animal, C for cat and D for dog. (See sample for details)

Output
For each case, output a single integer: the maximum number of happy children.

Sample Input

1 1 2
C1 D1
D1 C1

1 2 4
C1 D1
C1 D1
C1 D2
D2 C1

Sample Output

1
3

Hint

Case 2: Remove D1 and D2, that makes child 1, 2, 3 happy.

在动物园中,有N只猫和M只狗子,每个小朋友都有自己喜欢的动物,和自己讨厌的动物,而且如果小朋友喜欢狗子,那么他一定会讨厌猫;反之,如果她喜欢猫,那么她一定讨厌狗子。现在动物园打算移除一些动物,如果动物园移走了一个小朋友讨厌的动物留下了她喜欢的动物,那么她就会开心,现在求最多能让多少小朋友开心。
本来是像求出移除每个动物的开心值,然后排列所有组合。但是数据量太大了。
之后想,是不是要在小朋友和动物之间建立个关系,然后在操作一波出答案。但很不幸的是样例中两个有相同喜欢和讨厌的小朋友让这种方案直接凉了。
一共4种建边的方案,小朋友和动物不行,动物和动物看着就不行,那就人和人找个关系建个边了。
根据题意,人与人之间的关系可以分成如下三类:

  1. 我讨厌的你也讨厌
  2. 我讨厌的你喜欢
  3. 我讨厌的你既不喜欢也不讨厌

这三种情况中,1、3情况情况下,移除讨厌的动物会使开心值上升,而第2种情况下,由于这两个人有矛盾,所以开心值不增不减。如果把两人之间的矛盾关系建边的话,求最大开心值就变成了,找出一个点集,点集中所有的点之间都没有边,也就是这个图的最大独立集。因为题目已经确定,喜欢猫一定讨厌狗;喜欢狗一定讨厌猫,所以这个图也一定能分成一个二分图。
之后是如何求解最大独立集这个问题。简单一点呢,可以直接套用公式

| 最大独立集 | +  | 最小顶点覆盖 |  =  | 顶点数 |
| 最小顶点覆盖 | = | 最大匹配数 |

将问题转为求图的最大匹配。
具体解释来说,最小顶点覆盖是包含所有边端点的最小的点集,如果我们将最小定点覆盖中的点以及其相连的边都从图中移除,那么得到的图中就不存在任何边了,所剩的点也就是原图里的一个最大独立集。


#include <stdio.h>
#include <climits>
#include <cstring>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <utility>
#include <vector>
#include <string>

#define MAXN 505
#define STAR 505
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return

#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;

string like[505],dislike[505];
int match[MAXN];
bool used[MAXN];
vector<int> adj[MAXN];
bool dfs(int v);
inline bool cmp(int a,int b);
int main(){
    ios::sync_with_stdio(false);

    int n,m,p;
    while(cin>>n>>m>>p){
        rep(i,1,p+1){
            cin>>like[i]>>dislike[i];
        }
        
        rep(i,1,p+1)
            rep(j,1,i){
                if(cmp(i,j) || cmp(j,i)){
                    adj[i].Push(j);
                    adj[j].Push(i);
                }
            }

        int ans=0;
        memset(match,-1,sizeof(match));
        rep(i,1,p+1){
            memset(used,false,sizeof(used));
            if(dfs(i))
                ans++;
        }

        cout<<p-ans/2<<endl;

        rep(i,1,p+1)
            adj[i].clear();
    }
    re 0;
}
bool dfs(int v){
    rep(i,0,adj[v].size()){
        int u=adj[v][i],matched=match[u];
        if(!used[u]){
            used[u]=true;
            if(matched<0 || dfs(matched)){
                match[u]=v;
                return true;
            }
        }
    }
    return false;
}
inline bool cmp(int a,int b){
    if(like[a].size()!=dislike[b].size())
        return false;
    else{
        rep(i,0,like[a].size())
            if(like[a][i]!=dislike[b][i])
                return false;
        return true;
    }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值