1006: [HNOI2008]神奇的国度

76 篇文章 0 订阅
50 篇文章 0 订阅

1006: [HNOI2008]神奇的国度

Time Limit: 20 Sec   Memory Limit: 162 MB
Submit: 2583   Solved: 1169
[ Submit][ Status][ Discuss]

Description

K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2...An之间仅存在N对认识关系:(A1A2)(A2A3)...(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人 AB,BC,CD,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 4

Sample Output

3

HINT

一种方案(1,3)(2)(4)

Source



题解:

据说

弦图当图中任意长度大于3的环都至少有一个弦时, 一个无向图称为弦图。

一大波定义即将到来......
    子图: 图G = (V, E), 则G' = (V', E'), V'V, E'E 为图G的子图。

    团:图G的一个子图G' = (V', E') ,G'为关于V',的完全图。
    诱导子图:G =(V, E), G' = (V', E'), V'V, E' = {(u, v)|u,vV',(u, v)E} 中,G'称为图G的诱导子图。

    单纯点:设N(v)表示与点v相邻的点集。一个点称为单纯点当{v} + N(v)的诱导子图为一个团。
    完美消除序列:一个点的序列(每个点出现且恰好出现一次)v1, v2, …, vn满足vi在{vi, vi+1,…,vn}的诱导子图中为一个单纯点。

(最小染色=最大团数

¨最大势算法 Maximum Cardinality Search

·n1的顺序依次给点标号(标号为i的点出现在完美消除序列的第i)

·label[i]表示第i个点与多少个已标号的点相邻,每次选择label[i]最大的未标号的点进行标号。

¨判断一个序列是否为完美消除序列

·{vi+1,…,vn}中所有与vi相邻的点依次为vj1,…, vjk。只需判断vj1是否与vj2,…, vjk相邻即可。

¨本题就是用最少的颜色给每个点染色使得相邻的点染的颜色不同。

¨完美消除序列从后往前依次给每个点染上可以染的最小的颜色。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
#define N 10000 + 10
#define M 2000000 + 10
using namespace std;
struct edge{
	int to,next;
}e[M];
int n, m, num, ans, maxs;
int p[N], seq[N], col[N], lab[N], flag[N]; 
struct node{
    int now;  
	node *next;  
}f[N];//链表  
void add(int a,int b){
	e[++num].to=b;
	e[num].next=p[a];
	p[a]=num;
}
void put(int x){
	node *po = (struct node *)malloc(sizeof(struct node));  
	po->next = f[lab[x]].next;  
	po->now = x;  
    f[lab[x]].next = po;  
}//链表的插入  
void init(void){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
        add(a,b);
		add(b,a);
	}
}

void solve(void){
	//chu shi hua
	for(int i=1;i<=n;i++)f[i].next=NULL;
	for(int i=1;i<=n;i++)put(i);
	maxs=0;
	for(int i=n;i>=1;i--){
		node *po=f[maxs].next;
		while(flag[po->now]){
			f[maxs].next=po=po->next;
			while(po==NULL){
				maxs--;
				po=f[maxs].next;
			}
		}
		f[maxs].next=po->next;
		while(f[maxs].next==NULL)maxs--;
		int x=po->now;
		flag[x]=1,seq[i]=x;
		for(int t=p[x];t;t=e[t].next){
			if(!flag[e[t].to]){
				lab[e[t].to]++;
				if(lab[e[t].to]>maxs)maxs=lab[e[t].to];
				put(e[t].to);
			}
		}
	}
	//cout
	for(int i=1;i<=n;i++)flag[i]=-1;
	for(int i=n;i;i--){
		int x=seq[i];
		for(int t=p[x];t;t=e[t].next){
			flag[col[e[t].to]]=i;
		}
		for(int j=1;j<=n;j++){
			if(flag[j]!=i){
				col[x]=j;
				break;
			}
		}
		if(ans<col[x])ans=col[x];
	}
	cout<<ans;
}
int main()
{
	init();
	solve();
return 0;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值