题意:给出事件个数,然后给出访问的人数,之后给出事件,如果是1那么可以修改名称,如果是2证明某位朋友来访,如果此为朋友来访的时候正好是他的名字,那么就开心,问最后可以最多使多少位朋友开心?
题解:对于每次1后面的朋友之间相互连线,然后最后求解最大独立集,也就是求解它补图的最大团即可。刚开始自己写了一个暴搜+1个剪枝求解最大独立集T11,最后发现红书板子传送门,感觉自己好菜,我是主要负责的图论和dp,感觉实在是菜的不行,把专题刷完。
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int maxn=55;
int m,n;
bool g[maxn][maxn];
int len[maxn],ans,list[maxn][maxn],mc[maxn];
bool found;
void dfs(int size)
{
if(len[size]==0){
if(size>ans){
ans=size;
found=true;
}
}
for(int k=0;k<len[size]&&!found;k++){
if(size+len[size]-k<=ans){
break;
}
int i=list[size][k];
if(size+mc[i]<=ans){
break;
}
len[size+1]=0;
for(int j=k+1;j<len[size];j++){
if(g[i][list[size][j]]){
list[size+1][len[size+1]++]=list[size][j];
}
}
dfs(size+1);
}
}
void max_cluster()
{
mc[n]=ans=1;
for(int i=n-1;i;i--){
found=false;
len[1]=0;
for(int j=i+1;j<=n;j++){
if(g[i][j]){
list[1][len[1]++]=j;
}
}
dfs(1);
mc[i]=ans;
}
}
int main()
{
cin>>m>>n;
int cnt=0,opt;
string s;
map<string,int>ma;
set<int>se;
set<int>::iterator it1,it2;
memset(g,true,sizeof(g));
for(int i=1;i<=m;i++){
cin>>opt;
if(opt==1){
for(it1=se.begin();it1!=se.end();it1++){
for(it2=se.begin();it2!=se.end();it2++){
g[*it1][*it2]=false;
}
}
se.clear();
}else{
cin>>s;
if(ma.find(s)!=ma.end()){
se.insert(ma[s]);
}else{
ma[s]=++cnt;
se.insert(cnt);
}
}
}
for(it1=se.begin();it1!=se.end();it1++){
for(it2=se.begin();it2!=se.end();it2++){
g[*it1][*it2]=false;
}
}
max_cluster();
cout<<ans<<endl;
return 0;
}
还可以这样做,可以将朋友用对应的位置表示,然后用g数组表示出此位置与其他位置能相容的情况,之后就是记忆化搜索+状压了,每次都是考虑目前状态头部取或者不取,取的话就得&g,由于数组范围的限制,所以只能记忆化个1<<20的范围即可。
附上代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,op;
string s;
map<string,int>M;
ll g[50],dp[1<<20];
vector<ll>V;
int dfs(ll x){
int res=x>= (1<<20)?0:dp[x];
if(res==0&&x){
int j=63-__builtin_clzll(x);
res = max( dfs(x^ (1ll<<j)) ,dfs(x& (g[j]))+1 );
}
if(x<(1ll<<20))dp[x] =res;
return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>op;
if(op==1)V.push_back(0);
else{
cin>>s;
if(M.find(s)==M.end())M.insert({s, M.size()});
V.back() |= (1ll<<M[s]);
}
}
for(int i=0;i<m;i++)g[i]= (1ll<<m) -1;
for(int i=0;i<m;i++)g[i] &= ~(1ll<<i);
for(int i=0;i<V.size();i++){
for(int a=0;a<m;a++){
for(int b=0;b<m;b++){
if( ((V[i]>>a)&1) && ((V[i]>>b)&1) ){
g[a]&= ~(1ll<<b);
}
}
}
}
int ans = dfs((1ll<<m )-1);
cout<<ans<<endl;
return 0;
}