题目链接:http://codeforces.com/contest/1105/problem/E
题意:一共两种操作,1操作是改名字,2操作是朋友用名字访问,如果一个朋友每次访问的时候都是该朋友的名字,那这个朋友就会开心,求最多有几个开心的朋友
思路:每个1操作后面连续2操作的人只有一个可以被满足,所以这些人是互斥的,可以想到求最大独立集就是答案。读图的时候在互斥的人之间连边,然后做补图,最后求补图的最大团,即原图的最大独立集。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int maxn = 50;
#define INF 0xffffff
int mm[maxn][maxn];
map<string,int> name;
int n, m, Ans;
int Set[60], dp[maxn];
bool judge(int en, int point)
{
int i;
for (i = 1; i < en; i++)
{
if (!mm[Set[i]][point]) return false;
}
return true;
}
void dfs(int depth, int now)
{
if (depth + m - now + 1 <= Ans || depth + dp[now] <= Ans) return;
for (int i = now; i <= m; i++)
{
if (judge(depth + 1, i))
{
Set[depth + 1] = i;
dfs(depth + 1, i + 1);
}
}
if (depth > Ans) Ans = depth;
}
int main()
{
scanf("%d%d",&n,&m);
int tot = 1;
memset(mm,0,sizeof(mm));
vector<int> res;
for(int i=0;i<n;i++)
{
int k;
scanf("%d",&k);
if(k==1)
{
res.clear();
}
else
{
char str[maxn];
scanf("%s",str);
if(!name.count(str))
{
name[str] = tot++;
}
int f = 1;
for(int j=0;j<res.size();j++)
{
int tmp = res[j];
if(tmp==name[str])
{
f= 0;
break;
}
mm[name[str]][tmp] = mm[tmp][name[str]] = 1;
}
if(f)
res.push_back(name[str]);
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
mm[i][j]^=1;
}
}
Ans = 0;
dp[m] = 1;
for(int i=m-1;i>=1;i--)
{
Set[1] = i;
dfs(1,1+i);
dp[i] = Ans;
}
printf("%d\n",dp[1]);
}