首页 > 代码库 > 【BZOJ1006】【HNOI2008】神奇的国度

【BZOJ1006】【HNOI2008】神奇的国度

这回没看黄学长的代码,看的是chty的技术分享

原题:

K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA
相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2
...An之间仅存在N对认识关系:(A1A2)(A2A3)...(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人 AB,BC,C
D,DA相互认识,而AC,BD不认识.全民比赛时,为了防止做弊,规定任意一对相互认识的人不得在一队,国王相知道,
最少可以分多少支队。

1<=N<=10000,1<=M<=1000000

 

恩…建议先看一下cdq的《弦图与区间图》,你只要把内个东西看懂了这题就差不多了

首先这个图一定是弦图,题目中说的关系的性质就可以看成是弦图的定义

然后使用mcs求完美消除序列,这个可以在《弦图与区间图》中学习

然后根据消除序列从后往前染色即可

首先有一个非常严重的问题,团数并不是团的个数,而是最大团的节点的个数!!!

这个是NOIP吧里的证明:

首先团数<=色数 应该可以吧...
因为最大团的点必然每一个点的颜色不同...
接下来由于最大势算法求出的 那个 完美消除序列的每一个点都满足它与它后面的相连的点构成一个团,由于这个性质,考虑 节点 i 的时候 ,i后面与它相连的点都必然 是相互连接的, 也就是说 i 后面与它相连的点也是一个团。
考虑那个染色算法...我们染到第i个点的时候,由于上面的性质,与i相连的点必然相互染的是不同的颜色,所以我们考虑色数实际上就是考虑每一个点与它的相连的点构成的团的最大团数即可,所以 团数>=色数。
所以 团数=色数

勉强能理解吧……然后染色的时候从1开始枚举颜色,直到第i个颜色没有被周围的任何一个节点染色,这个节点的颜色就是i,然后维护最大的i,就是团数

这里有个小技巧,可以通过判断flag[color[e[j].y]]=i来判断i个颜色有没有被周围的任何一个节点染色,这样就不用memset了

代码:

技术分享
 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1;  char ch=getchar(); 8     while(ch<0||ch>9){if(ch==-)mark=-1;  ch=getchar();} 9     while(ch>=0&&ch<=9){z=(z<<3)+(z<<1)+ch-0;  ch=getchar();}10     return z*mark;11 }12 struct ddd{int next,y;}e[2100000];int LINK[11000],ltop=0;13 inline void insert(int x,int y){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;}14 int n,m;15 int label[11000];16 bool visited[11000];17 int peo[11000];18 int color[11000];19 int flag[11000];20 int ans=0;21 void mcs(){22     for(int i=n;i;i--){23         int now=0;24         for(int j=1;j<=n;j++)//注意这个label最大的点并不是和i相邻的点,而是全局点25             if(label[j]>=label[now] && !visited[j])  now=j;//这个循环一搞不就变成n^2的了???26         visited[now]=true;27         peo[i]=now;28         for(int j=LINK[now];j;j=e[j].next)29             label[e[j].y]++;30     }31 }32 void get_color(){33     for(int i=n;i;i--){34         int now=peo[i];35         for(int j=LINK[now];j;j=e[j].next)  flag[color[e[j].y]]=i;//标记成i的话就不用memset了36         int _color=1;37         while(flag[_color]==i)  _color++;38         color[now]=_color;39         ans=max(ans,_color);40     }41 }42 int main(){//freopen("ddd.in","r",stdin);43     memset(visited,0,sizeof(visited));44     cin>>n>>m;45     int _left,_right;46     while(m --> 0){47         _left=read(),_right=read();48         insert(_left,_right),insert(_right,_left);49     }50     mcs();51     get_color();52     cout<<ans<<endl;53     return 0;54 }
View Code

 

【BZOJ1006】【HNOI2008】神奇的国度