题目链接:http://codeforces.com/contest/1105/problem/E
题意:
给你n个操作和m个人,操作1是你可以将名字改成任意一个人的,操作2+name是name这个人会来看你的网站,如果一个人每次来发现你都是name这个名字,他会很开心,问你最优的名称修改使得开心的人数最多的人数是多少。
做法:
emmm很久之前的题了一直没补,因为要求是每次只能改成一个人的名字,所以在两次修改之间的不同的人之间都存在冲突关系,即有我没他。将这些人之间连一条边,那么答案就是最大独立集,(最大独立集是,一个被标记的点周围的点都不可以被标记,以至于标记出的最多的点数)。最大独立集就是补图的最大团,(搬出了我尘封已久的板子。。),板子套一下就好了。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
map<string,int> name;
map<int,int> mp;
int n,m,ct,ans,dp[55];
int g[55][55],incir[55];
vector<int> ve;
int gain(string na){
if(!name[na]) name[na]=++ct;
return name[na];
}
int iscircle(int num,int p){
for(int i=1;i<=num;i++){
if(g[incir[i]][p]==0) return 0;
}
return 1;
}
void dfs(int numv,int pos){
if(ans-numv>=n-pos+1||numv+dp[pos]<=ans) return ;
for(int i=pos;i<=m;i++){
if(iscircle(numv,i)){
incir[numv+1]=i;
dfs(numv+1,i+1);
}
}
if(numv>ans) ans=numv;
}
int main(){
scanf("%d%d",&n,&m);
rep(i,1,m){
rep(j,1,m){
g[i][j]=1;
}
}
int maxx=0;
rep(i,1,n){
int op; string na;
scanf("%d",&op);
if(op==1){
for(int i=0;i<ve.size();i++){
for(int j=i+1;j<ve.size();j++){
g[ve[i]][ve[j]]=0;
g[ve[j]][ve[i]]=0;
}
}
ve.clear();
mp.clear();
}
else{
cin>>na;
int x=gain(na);
if(!mp[x]) ve.push_back(x),mp[x]=1;
}
}
for(int i=0;i<ve.size();i++){
for(int j=i+1;j<ve.size();j++){
g[ve[i]][ve[j]]=0;
g[ve[j]][ve[i]]=0;
}
}
dp[m]=1;
for(int i=m-1;i>=1;i--){
incir[1]=i;
dfs(1,i+1);
dp[i]=ans;
}
printf("%d\n",dp[1]);
return 0;
}