[BZOJ]1006 [HNOI2008]神奇的国度

本题所给出的图显然满足弦图的定义,其主要性质与有关算法可以参考cdq的论文《弦图与区间图》。

这里以人为节点,人之间的认识关系就是边,而分组不能将互相认识的人分在一起,将一个组看成一种颜色的话,这就是一道最小染色的题目,但是朴素的染色方法会超时,我们可以使用弦图的性质来完成染色。而求弦图的最小染色,我们可以先求出弦图的完美消除序列,再将序列中的点顺序倒着用来贪心染色,所用到的颜色数就是答案。其实到这里就可以看着论文来写了,我就不细讲求完美染色序列的算法了。我的代码中使用了MCS算法来求,论文中也有提到。可以看着代码来理解下这个算法,不过我的算法达不到论文中的时间复杂度O(m+n)。我用堆维护最大值,复杂度就比这点大,原来应该要用桶维护的。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline void write(int x){
    if(x<0){putchar('-');x=-x;}
    if(x>=10) write(x/10);
    putchar(x%10+'0');
}
void writeln(int x){
    write(x);
    puts("");
}

const int N=10005;
int n,m;
vector<int> e[N];
int R[N],SA[N],label[N];                            //RA数组存完美消除序列中第几位是什么节点 
priority_queue <pair<int,int> > heap;               //默认大根堆 

void Construct(){
    fill(R+1,R+1+n,-1);                             //这里R数组是存节点在完美消除序列中是第几个 
    fill(label+1,label+1+n,0);                      //这里label数组是存节点的权值 
    for(int i=1;i<=n;i++)
        heap.push(make_pair(0,i));                  //将所有点都先加入heap中 
    for(int cnt=n;cnt>=1;){                         //这里就是求完美消除序列的主体了(虽然之前的初始化也是) 
        int id=heap.top().second;
        heap.pop();
        if(R[id]!=-1) continue;
        SA[cnt]=id; R[id]=cnt--;
        for(int i=0;i<e[id].size();i++){
            int u=e[id][i];
            if(R[u]!=-1) continue;
            label[u]++;
            heap.push(make_pair(label[u],u));
        }
    }
}

void color(int u){
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(label[v]==-1) continue;
        R[label[v]]=u;
    }
    for(int i=1;label[u]==-1;i++)
        if(R[i]!=u) label[u]=i;
}

int color_graph(){                                  //这里label数组与R数组重新定义了 
    fill(label+1,label+n+1,-1);                     //label数组是用来存该节点染了什么颜色 
    fill(R+1,R+1+n,-1);                             //R数组是存当前节点周围是否有此颜色 
    for(int i=n;i>0;i--) color(SA[i]);
    int ans=0;
    for(int i=1;i<=n;i++)
        ans=max(ans,label[i]);
    return ans;
}

int main(){
    n=read(); m=read();
    int u,v;
    for(int i=1;i<=m;i++){
        u=read(); v=read();
        e[u].push_back(v);
        e[v].push_back(u);
    }
    Construct();
    write(color_graph());
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值