方法:根据出现矛盾的两个观众序号建边。现在选择最多的顶点,要求各个顶点之间没有线相连,即不出现矛盾。就是求最大独立集。
最大匹配:二分图G中,找出边数最大的子图M,使得M中各条边均无公共顶点,则M为最大匹配。可用匈牙利算法求得。
最小顶点覆盖:二分图G中,找出顶点数最少的子图M,使得M中所有的点可以覆盖G中所有的边(一个顶点可以覆盖与它相连的边)。
最小顶点覆盖=最大匹配
#include <bits/stdc++.h> using namespace std; vector<int> line[503]; bool used[503]; int girl[503]; int n,m,k; bool find(int x){ for (int j=0;j<line[x].size();j++){ int jj=line[x][j]; if (used[jj]==false){ used[jj]=1; if (girl[jj]==-1 || find(girl[jj])) { girl[jj]=x; return true;}}} return false; } string a[503],b[503]; int main(){ int t; scanf("%d",&t); while(t--){ cin>>k>>m>>n; int all=0; for(int i=0;i<n;++i) line[i].clear(); memset(girl,-1,sizeof(girl)); for(int i=0;i<n;++i){ cin>>a[i]>>b[i]; for(int j=0;j<i;++j){ if(a[i]==b[j]||b[i]==a[j]){ line[i].push_back(j); line[j].push_back(i); } } } for (int i=0;i<n;i++){ memset(used,0,sizeof(used)); if (find(i)) all+=1; } cout<<n-all/2<<endl; //最小顶点覆盖,除2是因为两边有所重复 } return 0; }
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; struct node{ int cat,dog; }p1[505],p2[505]; int c,d,v,num1,num2; int s[505][505],vis[505],match[505]; int dfs(int x){ int i,j; for(i=1;i<num2;i++){ if(!vis[i]&&s[x][i]){ vis[i]=1; if(!match[i]||dfs(match[i])){ match[i]=x; return 1; } } } return 0; } int hungarian(){ int i,sum; sum=0; for(i=1;i<num1;i++){ memset(vis,0,sizeof(vis)); if(dfs(i)) sum++; } return sum; } //匈牙利算法模板 int main(){ //将喜欢猫的人放在左边的集合里喜欢狗的放在右面 int i,j,t,a,b; //将产生矛盾的连在一起再用v减掉,因此用到二分图 char ch; //匹配也就是匈牙利算法 scanf("%d",&t); while(t--){ scanf("%d%d%d",&c,&d,&v); num1=num2=1; for(i=1;i<=v;i++){ scanf(" %c%d %c%d",&ch,&a,&ch,&b); if(ch=='D'){ //喜欢猫的 p1[num1].cat=a; p1[num1++].dog=b; } else{ //喜欢狗的 p2[num2].cat=b; p2[num2++].dog=a; } } memset(s,0,sizeof(s)); memset(match,0,sizeof(match)); for(i=1;i<num1;i++) for(j=1;j<num2;j++) if(p1[i].cat==p2[j].cat||p1[i].dog==p2[j].dog) s[i][j]=1; printf("%d\n",v-hungarian()); } return 0; }