Problem Description
K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA
相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2
...An之间仅存在N对认识关系:(A1A2)(A2A3)...(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人 AB,BC,C
D,DA相互认识,而AC,BD不认识.全民比赛时,为了防止做弊,规定任意一对相互认识的人不得在一队,国王相知道,
最少可以分多少支队。Input
第一行两个整数N,M。1<=N<=10000,1<=M<=1000000.表示有N个人,M对认识关系. 接下来M行每行输入一对朋
友Output
输出一个整数,最少可以分多少队
Sample Input
4 5
1 2
1 4
2 4
2 3
3 4Sample Output
3
思路:将 n 个人 m 个关系视为 n 个点 m 条边,从而构成一个图,根据关系的描述可知,构成的图是一个弦图,而题目本质上就是要求最小着色数,对于弦图来说,直接跑 MCS 后求取最大的 label[i]+1 即可
Source Program
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
const double EPS = 1E-10;
const int MOD = 1E9+7;
const int N = 1000000;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;
struct Edge {
int to,next;
Edge() {}
Edge(int to,int next):to(to),next(next) {}
};
struct MCS{
Edge edge[N<<1];
int head[N],tot;
int n,m;
bool vis[N];
int id[N];//编号
int label[N];//与多少标号点相邻
int order[N];//完美消除序列
vector<int> V[N];
void init(int n,int m) {
this->n=n;
this->m=m;
for(int i=1; i<=n; i++)
V[i].clear();
memset(head,-1,sizeof(head));
memset(order,0,sizeof(order));
memset(label,0,sizeof(label));
memset(vis,0,sizeof(vis));
memset(id,0,sizeof(id));
tot=0;
}
void addEdge(int x,int y) {
edge[tot].to=y;
edge[tot].next=head[x];
head[x]=tot++;
}
void mcs() {
for(int i=1; i<=n; i++)
V[0].push_back(i);
int maxx=0;
int now=0;
for(int i=1; i<=n; i++) { //从前往后
bool flag=false;
while(!flag) {
for(int j=V[maxx].size()-1; j>=0; j--) { //从后往前
if(vis[V[maxx][j]])
V[maxx].pop_back();
else {
flag=true;
now=V[maxx][j];
break;
}
}
if(!flag)
maxx--;
}
vis[now]=true;
//逆序存放
order[n-i+1]=now;
id[now]=n-i+1;
for(int j=head[now]; j!=-1; j=edge[j].next) {
int to=edge[j].to;
if(!vis[to]) {
label[to]++;
V[label[to]].push_back(to);
maxx=max(maxx,label[to]);
}
}
}
}
int bucket[N];//桶
int judge() { //判断是否是弦图
memset(vis,0,sizeof(vis));
memset(bucket,0,sizeof(bucket));
for(int i=n; i>0; i--) {
int cnt=0;
int ret=1;
for(int j=head[order[i]]; j!=-1; j=edge[j].next)
if(id[edge[j].to]>i)
vis[bucket[++cnt]=edge[j].to]=1;
for(int j=head[bucket[1]]; j!=-1; j=edge[j].next) {
int to=edge[j].to;
if(to!=bucket[1]&&vis[to]) {
if(vis[to]) {
ret++;
vis[to]++;
}
}
}
for(int j=1; j<=cnt; j++)
vis[bucket[j]]=0;
if(cnt&&ret!=cnt)
return false;
}
return true;
}
int getMaximumClique() { //计算最大团、最小着色
int res=0;
for(int i=1; i<=n; i++)
res=max(res,label[i]+1);
return res;
}
int getMaximumIndependentSet() { //计算最大独立集、最小团覆盖
memset(vis,0,sizeof(vis));
int res=0;
for(int i=1; i<=n; i++) {
if(!vis[order[i]]) {
res++;
vis[order[i]]=true;
for(int j=head[order[i]]; j!=-1; j=edge[j].next)
vis[edge[j].to]=true;
}
}
return res;
}
}mcs;
int main() {
int n,m;
scanf("%d%d",&n,&m);
mcs.init(n,m);
for(int i=1; i<=m; i++) {
int x,y;
scanf("%d%d",&x,&y);
mcs.addEdge(x,y);
mcs.addEdge(y,x);
}
mcs.mcs();
int res=mcs.getMaximumClique();//最大团、最小着色
printf("%d\n",res);
return 0;
}