LA 3415 保守的老师
题目链接:https://vjudge.net/contest/161820#problem/E
题意:
有一些同学,要从中选出一些同学来,人数尽量多,但是,两两之间要满足至少一个条件(身高差>40,性别相同,。。。)
分析:
最大独立集:尽量选择多的结点,任意两个结点不相邻;
男同学X,女同学Y,如果可能产生关系,连一条边,这样这两个人就不会在一起;
最大独立集=n-最大匹配
证明:
最小点覆盖 = 对于每一条边,至少有一个点要被选中
最大独立集 = 对于每一条边,最多一个点被选中
从定义中可以看出,这两个是互补的;
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 500+5; 6 7 struct BPM { 8 int n,m; 9 vector<int> G[maxn]; 10 int left[maxn]; 11 bool T[maxn]; 12 13 int right[maxn]; 14 bool S[maxn]; 15 16 void init(int n,int m) { 17 this->n = n; 18 this->m = m; 19 for(int i=0;i<n;i++) 20 G[i].clear(); 21 } 22 23 void AddEdge(int u,int v) { 24 G[u].push_back(v); 25 } 26 27 bool match(int u) { 28 S[u] = true; 29 for(int i=0;i<G[u].size();i++) { 30 int v = G[u][i]; 31 if(!T[v]) { 32 T[v] = true; 33 if(left[v]==-1||match(left[v])) { 34 left[v] = u; 35 right[u] = v; 36 return true; 37 } 38 } 39 } 40 return false; 41 } 42 43 int solve() { 44 memset(left,-1,sizeof(left)); 45 memset(right,-1,sizeof(right)); 46 int ans = 0; 47 for(int u=0;u<n;u++) { 48 memset(S,0,sizeof(S)); 49 memset(T,0,sizeof(T)); 50 if(match(u)) 51 ans++; 52 } 53 return ans; 54 } 55 56 }sol; 57 58 struct Student { 59 int h; 60 string music,sport; 61 Student(int h,string music,string sport):h(h),music(music),sport(sport) {} 62 }; 63 64 bool conflict(const Student& a,const Student& b) { 65 return abs(a.h-b.h)<=40&&a.music ==b.music && a.sport!=b.sport; 66 } 67 68 int main() 69 { 70 int t; 71 cin>>t; 72 while(t--) { 73 int n; 74 cin>>n; 75 vector<Student> male,female; 76 for(int i=0;i<n;i++) { 77 int h; 78 string gender,music,sport; 79 cin>>h>>gender>>music>>sport; 80 if(gender[0]=='M') male.push_back(Student(h,music,sport)); 81 else female.push_back(Student(h,music,sport)); 82 } 83 int x = male.size(); 84 int y = female.size(); 85 sol.init(x,y); 86 for(int i=0;i<x;i++) 87 for(int j=0;j<y;j++) 88 if(conflict(male[i],female[j])) 89 sol.AddEdge(i,j); 90 printf("%d\n",x+y-sol.solve()); 91 } 92 return 0; 93 }