BZOJ 1006 [HNOI2008]神奇的国度==最大势算法

神奇的国度

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 4

Sample Output

3

Hint

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

 

这个还未理解,貌似是弦图有关知识。

根据提题意,不难看出,所有的人构成的关系图是一个弦图(长度超过 3 的环中必有一条弦),求出它的完美性消除序列,根据完美消除序列逆序贪心的染色,最终所用的色数就是本题的答案

 

完美消除序列的求法:

 

使用陈丹琦讲述的 MCS 法,可以在 o(n+m) 的时间复杂度中求出一个图的完美消除序列,并在 o(n+m) 的时间复杂度下判断这个完美消除序列是否合法,不过,我不知道怎么在 o(n+m) 的时间复杂度下求出这个完美消除序列,或许是利用桶优化吧,我写了个堆优化的,时间复杂度也能接受

 

求完美消除序列的 MCS 法是倒着解的,也就是先求序列的第 n 个再求序列的第 n-1 个

每次选取图中具有最大标号的点作为完美消除序列中对应位置的点,并用这个点更新所有和他邻接的不再序列中的点的标号值

 

对于一个弦图的染色,用完美消除序列可以很好的解决,按照完美消除序列中的点倒着给图中的点贪心的然尽可能小的颜色

最终,一定能够用最小的颜色数量给图中的所有点染色

 

本题可以先求出来这个弦图的完美消除序列,由于一定是一个弦图,所以序列一定合法,直接根据消除序列染色就行

 

更多的和弦图区间图相关的知识,请看陈丹琦的PPT:弦图与区间图

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define N 10007
 7 #define M 2000007
 8 using namespace std;
 9 
10 int n,m,ans;
11 int cnt,head[N],next[M],rea[M];
12 int d[N],q[N],col[N],hash[N];
13 bool vis[N];
14 
15 void add(int u,int v)
16 {
17     cnt++;
18     next[cnt]=head[u];
19     head[u]=cnt;
20     rea[cnt]=v;
21 }
22 int main()
23 {
24     memset(head,-1,sizeof(head));
25     scanf("%d%d",&n,&m);
26     int x,y;
27     for(int i=1;i<=m;i++)
28     {
29         scanf("%d%d",&x,&y);
30         add(x,y),add(y,x);
31     }
32     for(int i=n;i>=1;i--)
33     {
34         int t=0;
35         for(int j=1;j<=n;j++) if(!vis[j]&&d[j]>=d[t])t=j; //找未标记的度数最大的点。 
36         vis[t]=1;q[i]=t;
37         for(int j=head[t];j!=-1;j=next[j]) d[rea[j]]++;
38         }
39     for(int i=n;i>=1;i--)
40     {
41         int t=q[i];
42         for(int j=head[t];j!=-1;j=next[j])
43             hash[col[rea[j]]]=i;
44         int j;
45         for(j=1;j<=n;j++) 
46             if(hash[j]!=i) break;
47         col[t]=j;
48         if(j>ans)ans=j;
49     }
50     printf("%d",ans);
51 }

 

转载于:https://www.cnblogs.com/fengzhiyuan/p/7632863.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值