HDU 3829 Cat VS Dog (最大独立点集)

这道题,要好好写一下总结。

开始的时候,我把猫和狗作为顶点,求最大独立点集,但是后来发现,这个是有问题的。画了一个图,然后模拟了样例2,发现这个边可以重复,也就是说可有不同的小孩的like和dislike是一样的,那么这中情况下,删除一个点,可是多少个孩子高兴就不一定了。

于是感觉到这建图是有问题的。

仔细分析一下题目,说删除一个孩子不喜欢的动物,会使这个孩子,但是喜欢这个动物的孩子就会不高兴,想让高兴的孩子尽可能的多,那么就要删除尽可能少的有孩子喜欢的动物,也就是说孩子和孩子之间是有冲突的,一旦孩子和孩子有冲突,对于两个有冲突的孩子来讲,只能满足一个孩子,那么如果两个孩子之间没有冲突,那么就最多能满足两个孩子,那么进一步讲,如果三个孩子1, 2, 3有冲突的话,情况有两种,第一是1讨厌的是2喜欢的,也是3喜欢的,这样的情况下2和3没有冲突,因为喜欢的是一样,最多可以使得两个孩子高兴,第二是1喜欢的是2讨厌也是3讨厌的,那么也就是说2和3讨厌的是一样的,喜欢不一样也无所谓,最多让两个孩子高兴,那如果是4个孩子呢,其实也是一样的,灭有办法让四个孩子都高兴。因此,如果这些孩子不冲突,那么就可以让每个孩子都高兴!这样的话,就是说我们可以找到最多不冲突的孩子们,注意是孩子们。为什么呢?或者说如何证明呢?首先我们可以确定的是相互不冲突的孩子是都可以满足的,假设最多有m个孩子不冲突,那么我们可以满足m个孩子,如果我们试图在m个孩子之外,还想让更多的孩子高兴,那么必然要删除动物,而这个动物必然是某一个孩子喜欢的,而另外还有至少一个孩子不喜欢的(因为没有冲突的孩子都别满足了,剩下的孩子都是和其他孩子(这里面包括已经被满足的孩子)有冲突的,一旦满足了剩下的孩子中的一个,必然有至少1个孩子不被满足,也就是说宅原来被满足的孩子中至少有一个孩子从被满足的状态转到不被满足的状态!因此,这道题,就是求最大独立点集!

同时,求最大独立点集的时候,要注意的如何建图,有时候可以反向建图,主要是找边,谁和谁可以连上边!这道题,就是将孩子作为节点,将有冲突的孩子之间连一条边,求最大独立点集!

代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;

const int N = 600;
int n, m, p;
string like[N], dislike[N];
int bmap[N][N], cy[N];
bool vis[N];

bool dfs( int u )
{
    for ( int v = 1; v <= p; ++v ) if ( bmap[u][v] && !vis[v] ) {
        vis[v] = 1;
        if ( cy[v] == -1 || dfs( cy[v] ) ) {
            cy[v] = u;
            return 1;
        }
    }
    return 0;
}
int match()
{
    int res = 0; 
    memset( cy, -1, sizeof(cy) );
    for ( int i = 1; i <= p; ++i ) {
        memset( vis, 0, sizeof(vis));
        if ( dfs( i ) ) res++;
    }
    return res;
}
int main()
{
    while ( scanf("%d%d%d", &n, &m, &p) == 3 ) {
        memset( bmap, 0, sizeof(bmap));
        for ( int i = 1; i <= p; ++i ) { 
            cin >> like[i] >> dislike[i];
        }
        for ( int i = 1; i <= p; ++i ) 
            for ( int j = i+1; j <= p; ++j ) 
                if ( like[i] == dislike[j] || like[j] == dislike[i] ) bmap[i][j] = bmap[j][i] = 1;
        printf("%d\n", p-match()/2);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值