hdu Cat vs. Dog (最大匹配 ——最大独立集)

来源:互联网 发布:报纸编辑软件 编辑:程序博客网 时间:2024/06/05 00:29

Cat vs. Dog

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 5   Accepted Submission(s) : 2

Font: Times New Roman | Verdana | Georgia

Font Size: ← →

Problem Description

The latest reality show has hit the TV: ``Cat vs. Dog''. In this show, a bunch of cats and dogs compete for the very prestigious Best Pet Ever title. In each episode, the cats and dogs get to show themselves off, after which the viewers vote on which pets should stay and which should be forced to leave the show.Each viewer gets to cast a vote on two things: one pet which should be kept on the show, and one pet which should be thrown out. Also, based on the universal fact that everyone is either a cat lover (i.e. a dog hater) or a dog lover (i.e. a cat hater), it has been decided that each vote must name exactly one cat and exactly one dog.Ingenious as they are, the producers have decided to use an advancement procedure which guarantees that as many viewers as possible will continue watching the show: the pets that get to stay will be chosen so as to maximize the number of viewers who get both their opinions satisfied. Write a program to calculate this maximum number of viewers.

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:* One line with three integers c, d, v (1 ≤ c, d ≤ 100 and 0 ≤ v ≤ 500): the number of cats, dogs, and voters.* v lines with two pet identifiers each. The first is the pet that this voter wants to keep, the second is the pet that this voter wants to throw out. A pet identifier starts with one of the characters `C' or `D', indicating whether the pet is a cat or dog, respectively. The remaining part of the identifier is an integer giving the number of the pet (between 1 and c for cats, and between 1 and d for dogs). So for instance, ``D42'' indicates dog number 42.

Output

Per testcase:* One line with the maximum possible number of satisfied voters for the show.

Sample Input

21 1 2C1 D1D1 C11 2 4C1 D1C1 D1C1 D2D2 C1

Sample Output

13

Source

NWERC 2008

这道题开始怎么想都想不出来怎么用匹配做,后来才知道要利用二分图最大匹配的性质:
有如下三条,现在这个题中记录着,以后再专研各类性质的应用
A. 一个二分图中的最大匹配数等于这个图中的最小点覆盖数
B.最小路径覆盖=|G|-最大匹配数
(最小路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点)
C.二分图最大独立集=顶点数-二分图最大匹配
(独立集:图中任意两个顶点都不相连的顶点集合)

这道题要用到第三条性质。
就是把所有人看做二分图中的点,如果两个人的选择有矛盾,
就代表这两个点之间可以匹配。
那么这个二分图的独立集就是不会有矛盾的人,
样最大独立集就是我们需要求的最大人数。
再利用定理求解即可,需要注意的是,
由于这个二分图的两个集合是一样的,且可匹配的边是对称的,
所以最后得到的值除以2就是所求的最大匹配,
正确性的证明我还不明白,先这样记着吧。

#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <algorithm>using namespace std;#define M 510#define N 250010int Head[M] , Next[N] , Key[N];int match[M];string like[M] , dislike[M];bool visit[M];int num , child;void add( int u, int v ){     Key[num] = v;     Next[num] = Head[u];     Head[u] = num++;}bool find( int u ){     int temp;     for( int i=Head[u] ; i != -1 ; i=Next[i] )     {          temp = Key[i];          if( !visit[temp] )          {              visit[temp] = true;              if( match[temp] == -1 || find(match[temp]) )              {                  match[temp] = u;                  return true;              }          }     }     return false;}int hungary(  ){    int sum = 0 ;    for( int i=0 ; i<child ; i++ )    {         memset( visit , false , sizeof(visit) );         if( find(i) )             sum++;    }    return sum;}int main( ){    int cat , dog;    string likeit , dislikeit;    while( scanf("%d%d%d",&cat,&dog,&child) != EOF )    {           num = 0;           memset( Head , -1 , sizeof(Head) );           memset( match , -1 , sizeof(match) );           for( int i=0 ; i<child ; i++ )           {                cin >> likeit >> dislikeit;                like[i] = likeit;                dislike[i] = dislikeit;           }           for( int i=0 ; i<child ; i++ )           {                for( int j=0 ; j<child ; j++ )                     if( like[i].compare(dislike[j]) ==0 || dislike[i].compare(like[j]) ==0 )                         add( i,j );           }           printf("%d\n",child-hungary()/2);    }    return 0 ;}