BZOJ 1006 [HNOI2008]神奇的国度 弦图的最小染色
2015-10-20 13:54
267 查看
题意:
给定一张弦图,相邻的点不同色,求需要的最少颜色个数。
解析:
解法参见CDQ的论文…
至于MCS最大势算法的O(n+m)实现办法参见金策在贴吧的留言…
对于本题来说,解法就是先求出该弦图的完美消除序列(MCS算法即可),然后因为MCS算法求出来的完美消除序列顺序是倒着的,所以我们倒着枚举每个点,寻找每个点能染得最小颜色。
MCS算法的O(n+m)实现就是我们需要维护每个点相邻有多少个点被染色,以及每个点是否被染色,以及目前最大的势是多少。
然后对于每个势的值,我们挂一个链表。
每一次在最大的势的链上查找第一位未被染色的点,如果查到被染色的点的话,在该链上删去这个点,如果在最大的势的链上没有查到未被染色的点的话,把最大的势减1继续查即可。
选完一个点后更新这个点相邻的点的势,直接往新的势的值上挂链即可,并不需要把原来的删掉。
在这个过程同时维护最大势的值。
把如上过程重复n次。
容易证明添加删除是在O(m)复杂度下的。
所以总复杂度O(n+m)。
正确性参见CDQ论文
代码:
给定一张弦图,相邻的点不同色,求需要的最少颜色个数。
解析:
解法参见CDQ的论文…
至于MCS最大势算法的O(n+m)实现办法参见金策在贴吧的留言…
对于本题来说,解法就是先求出该弦图的完美消除序列(MCS算法即可),然后因为MCS算法求出来的完美消除序列顺序是倒着的,所以我们倒着枚举每个点,寻找每个点能染得最小颜色。
MCS算法的O(n+m)实现就是我们需要维护每个点相邻有多少个点被染色,以及每个点是否被染色,以及目前最大的势是多少。
然后对于每个势的值,我们挂一个链表。
每一次在最大的势的链上查找第一位未被染色的点,如果查到被染色的点的话,在该链上删去这个点,如果在最大的势的链上没有查到未被染色的点的话,把最大的势减1继续查即可。
选完一个点后更新这个点相邻的点的势,直接往新的势的值上挂链即可,并不需要把原来的删掉。
在这个过程同时维护最大势的值。
把如上过程重复n次。
容易证明添加删除是在O(m)复杂度下的。
所以总复杂度O(n+m)。
正确性参见CDQ论文
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 10010 #define M 1000100 using namespace std; int n,m; int head ,cnt,head_link ,cnt_link; struct node { int from,to,next; }edge[M<<2],Link[M<<2]; bool vis ; int best; void init() { memset(head,-1,sizeof(head)); memset(head_link,-1,sizeof(head_link)); cnt=1,cnt_link=1; } void linkadd(int from,int to) { Link[cnt_link].from=from,Link[cnt_link].to=to,Link[cnt_link].next=head_link[from]; head_link[from]=cnt_link++; } void edgeadd(int from,int to) { edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from]; head[from]=cnt++; } int sta ,height ; int top; void getsta() { int tmp=n; while(tmp) { int flag=0,choose; while(!flag) { for(int i=head_link[best];i!=-1;i=Link[i].next) { int to=Link[i].to; if(vis[to]){head_link[best]=Link[i].next;continue;} flag=1,vis[to]=1,choose=to;break; } if(!flag) best--; } sta[++top]=choose; for(int i=head[choose];i!=-1;i=edge[i].next) { int to=edge[i].to; if(vis[to])continue; height[to]++; linkadd(height[to],to); best=max(best,height[to]); } tmp--; } } int mark ; int color ; int main() { init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); edgeadd(x,y); edgeadd(y,x); } for(int i=1;i<=n;i++) linkadd(0,i); getsta(); int ans=0; for(int i=1;i<=top;i++) { int x=sta[i]; for(int j=head[x];j!=-1;j=edge[j].next) mark[color[edge[j].to]]=i; for(int j=1;j<=n;j++) { if(mark[j]==i)continue; else {color[x]=j;break;} } ans=max(ans,color[x]); } printf("%d\n",ans); }
相关文章推荐
- java动态代理(JDK和cglib)
- decorView和window之间的层级及关系
- ls --color的使用
- 结构型模式之四——外观模式
- php解决key没有双引号的问题
- 观察变量值修改的位置
- 硬币问题(贪心)
- GRUB- "No suitable mode found"
- handsontable-chosen-editor
- JS日期时间类型(Y-m-d H:i:s)与时间戳互转
- Request的getParameter和getAttribute方法的区别
- 如何修改MFC的图标
- MDK Executing a function or an interrupt handler in RAM
- Window窗口布局 --- DecorView浅析
- 你应该知道的 RPC 原理
- 网址
- 接口类与抽象类的区别
- nmon的使用
- zookeeper原理(转)
- 简单的分析网易热这款产品