首先,由最大势算法求出完美消除序列。方法为,首先所有点的lab值为0,lab值表示有多少个已经标号的点与x相邻,首先任意找一个点,标号为n(注意是倒序标号),然后与它相连的点的lab值++,然后再找,直到所有点都在完美消除序列中,然后倒序染色,染色方法是从找一个mex{与它相邻的点的颜色}染上,然后所用的颜色即为最小。
正确性保证:因为完美消除序列的性质,i之后的点与i构成的是一个团,那么由小团染到大团(从后往前)的方案一定是最优的。
鸣谢zzy大佬
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn=2000010;
int topt,st[maxn],nt[maxn],to[maxn],n,m,xx,yy,ans,now;
int a[maxn],in[maxn],col[maxn],vis[maxn];
bool f[maxn];
inline void add( int x, int y)
{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}
int main()
{
scanf ( "%d%d" ,&n,&m);
for ( int i=1;i<=m;i++)
{ scanf ( "%d%d" ,&xx,&yy); add(xx,yy); add(yy,xx);}
for ( int i=n;i>=1;i--)
{
now=-1; int lc=0;
for ( int j=1;j<=n;j++)
if (in[j]>now && !f[j]) {now=in[j]; lc=j;}
a[i]=lc; f[lc]=1;
int p=st[lc];
while (p) {in[to[p]]++; p=nt[p];}
}
for ( int i=n;i>=1;i--)
{
int p=st[a[i]];
while (p) {vis[col[to[p]]]=i; p=nt[p];}
int j=1;
while (vis[j]==i) j++;
ans=max(ans,j); col[a[i]]=j;
}
printf ( "%d\n" ,ans);
return 0;
}
|