题目大意:
在 n 个点间有 m 种颜色的检查点,按顺序扫过所有点,在每个点处可改变颜色,如果与某个检查点颜色相同,则满足该检查点,求最多能满足几种颜色的检查点。
思路:
每两个点间的所有检查点只可满足一个,即满足一个剩下的都不能满足。
将两个点间的检查点颜色两两连一条边
最后选取最多颜色即在构建的图中选出最多的互不连接的点,即该图的最大独立集
G的最大独立集 = G的补图的最大团
所以答案即为构建好的图的补图的最大团
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50;
int n,m,x,sz,now,mx;
int s[maxn],clique[maxn];
int can[maxn][maxn];
int dp[maxn];
bool g[maxn][maxn];
char str[50];
map<string,int> msi;
vector<int> pre;
bool dfs(int t,int cnt)
{
if(t == 0)
{
if(cnt > mx)
{
mx = cnt;
for(int i = 0; i < mx; i++)
clique[i] = s[i];
return true;
}
return false;
}
for(int i = 0; i < t; i++)
{
if(cnt + t - i <= mx) return false;
if(cnt + dp[can[cnt][i]] <= mx) return false;
int k = 0;
s[cnt] = can[cnt][i];
for(int j = i + 1; j < t; j++)
{
if(g[can[cnt][i]][can[cnt][j]])
can[cnt + 1][k++] = can[cnt][j];
}
if(dfs(k, cnt + 1)) return false;
}
return false;
}
void maxclique()
{
mx = 1;
for(int i = sz - 1; i >= 1; i--)
{
int k = 0;
s[0] = i;
for(int j = i + 1; j < sz; j++)
{
if(g[i][j]) can[1][k++] = j;
}
dfs(k,1);
dp[i] = mx;
}
}
int main()
{
scanf("%d%d",&n,&m);
sz = 1;
memset(g, 1, sizeof(g));
for(int i = 0; i < n; i++)
{
scanf("%d",&x);
if(x == 1) pre.clear();
else
{
scanf("%s",str);
if(!msi[str]) msi[str] = sz++;
now = msi[str];
for(int i = 0; i < pre.size(); i++)
{
g[now][pre[i]] = false;
g[pre[i]][now] = false;
}
pre.push_back(now);
}
}
mx = 0;
maxclique();
printf("%d\n",mx);
}