知识点
最大独立集(set) = 补图的最大团(clique )
最小顶点覆盖 + 最大独立集 = V
Hiasat registered a new account in NeckoForces and when his friends found out about that, each one of them asked to use his name as Hiasat's handle.
Luckily for Hiasat, he can change his handle in some points in time. Also he knows the exact moments friends will visit his profile page. Formally, you are given a sequence of events of two types:
- 11 — Hiasat can change his handle.
- 22 ss — friend ss visits Hiasat's profile.
The friend ss will be happy, if each time he visits Hiasat's profile his handle would be ss.
Hiasat asks you to help him, find the maximum possible number of happy friends he can get.
The first line contains two integers nn and mm (1≤n≤105,1≤m≤401≤n≤105,1≤m≤40) — the number of events and the number of friends.
Then nn lines follow, each denoting an event of one of two types:
- 11 — Hiasat can change his handle.
- 22 ss — friend ss (1≤|s|≤401≤|s|≤40) visits Hiasat's profile.
It's guaranteed, that each friend's name consists only of lowercase Latin letters.
It's guaranteed, that the first event is always of the first type and each friend will visit Hiasat's profile at least once.
Print a single integer — the maximum number of happy friends.
5 3 1 2 motarack 2 mike 1 2 light
2
4 3 1 2 alice 2 bob 2 tanyaromanova
1
In the first example, the best way is to change the handle to the "motarack" in the first event and to the "light" in the fourth event. This way, "motarack" and "light" will be happy, but "mike" will not.
In the second example, you can choose either "alice", "bob" or "tanyaromanova" and only that friend will be happy.
题意 m个朋友 n个操作
两种操作
1 Hiasat 可以修自己的id为任意值
2 Hiasat 得一个朋友查看id
当且仅当 他的朋友每次查看id都为自己的名字才是高兴的
解析 很容易想到两个1之间的朋友是互斥的 只能使其中一名朋友高兴,我们在互斥的朋友之间连一条无向边,从而转化成求无向图的最大独立集问题。
AC代码
1 #include <bits/stdc++.h> 2 #define pb push_back 3 #define mp make_pair 4 #define fi first 5 #define se second 6 #define all(a) (a).begin(), (a).end() 7 #define fillchar(a, x) memset(a, x, sizeof(a)) 8 #define huan printf(" ") 9 #define debug(a,b) cout<<a<<" "<<b<<" "<<endl 10 #define ffread(a) fastIO::read(a) 11 using namespace std; 12 const int maxn = 1e5+10; 13 const int maxm = 1e4+10; 14 const int inf = 0x3f3f3f3f; 15 const int mod = 998244353; 16 const double epx = 1e-6; 17 typedef long long ll; 18 const ll INF = 1e18; 19 const double pi = acos(-1.0); 20 //head------------------------------------------------------------------ 21 int G[100][100]; 22 int ans,cnt[100],group[100],n,m,vis[100];//ans表示最大团,cnt[N]表示当前最大团的节点数,group[N]用以寻找一个最大团集合 23 map<string,int> pm; 24 int tot = 0; 25 struct node 26 { 27 int op; 28 string s; 29 } Q[maxn]; 30 vector<int> v; 31 bool dfs(int u,int pos)//u为当从前顶点开始深搜,pos为深搜深度(即当前深搜树所在第几层的位置) 32 { 33 int i,j; 34 for(i=u+1; i<=tot; i++) //按递增顺序枚举顶点 35 { 36 if(cnt[i]+pos<=ans) 37 return 0;//剪枝 38 if(G[u][i]) 39 { 40 // 与目前团中元素比较,取 Non-N(i) 41 for(j=0; j<pos; j++) 42 if(!G[i][vis[j]]) 43 break; 44 if(j==pos) 45 { 46 // 若为空,则皆与 i 相邻,则此时将i加入到 最大团中 47 vis[pos]=i;//深搜层次也就是最大团的顶点数目,vis[pos] = i表示当前第pos小的最大团元素为i(因为是按增顺序枚举顶点 ) 48 if(dfs(i,pos+1)) 49 return 1; 50 } 51 } 52 } 53 if(pos>ans) 54 { 55 for(i=0; i<pos; i++) 56 group[i] = vis[i]; // 更新最大团元素 57 ans = pos; 58 return 1; 59 } 60 return 0; 61 } 62 void maxclique()//求最大团 63 { 64 ans=-1; 65 for(int i=tot; i>0; i--) 66 { 67 vis[0]=i; 68 dfs(i,1); 69 cnt[i]=ans; 70 } 71 } 72 int main() 73 { 74 scanf("%d%d",&n,&m); 75 for(int i=1; i<=n; i++) 76 { 77 int op; 78 string tmp; 79 scanf("%d",&op); 80 if(op==1) 81 Q[i].op = op; 82 else 83 { 84 cin>>tmp; 85 Q[i].op = op; 86 Q[i].s = tmp; 87 if(!pm[tmp]) 88 pm[tmp] = ++tot; 89 } 90 } 91 memset(G,inf,sizeof(G)); 92 Q[n+1].op=1; 93 for(int i=1; i<=n+1; i++) 94 { 95 if(Q[i].op==1) 96 { 97 for(int j=0; j<v.size(); j++) 98 { 99 for(int k=j+1; k<v.size(); k++) 100 { 101 G[v[k]][v[j]] = 0; 102 G[v[j]][v[k]] = 0; 103 } 104 } 105 v.clear(); 106 } 107 else 108 { 109 v.push_back(pm[Q[i].s]); 110 } 111 } 112 maxclique(); 113 if(ans<0) 114 ans = 0; 115 printf("%d ",ans); 116 return 0; 117 }