[bzoj4878]挑战NP-Hard

题目描述

天才大学生quailty热衷于解决NP-Hard问题,你如果AC 了这道题,就可以成为他真正的粉丝。图染色问题:给定
无向图G和一个正整数k。对于图中的每个点,选择一个在[1,k]之间的整数作为其颜色。你需要保证对于每条边,
其两端点的颜色均不相同。简单k路径问题:给定无向图G和一个正整数k。请找到一条经过了恰好k条边的简单路径
。即,你需要找到一个长度为k+1的序列v_1,v_2,…,v_{k+1},满足1<=v_i<=n,且任意两个v均不相同,同时v_i
与v_{i+1}之间存在一条边。现在给定无向图G和一个正整数k,quailty知道你没有他的水平,所以你只需解决上面
的任意一个问题就可以成为他的粉丝。

好题

我们对图进行如下染色:一个点的颜色是相邻节点颜色的mex(没染的颜色记作0)。
如果我们最后这样使得染出的最大颜色不超过k,就解决了第一个问题。
否则,我们找到一个颜色为k+1的, 一定有一个颜色为k的与它相邻,同样有k-1……这样找到了一条长度为k+1的简单路径,就解决了第二个问题。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=10000+10,maxm=100000+10;
int ans[maxn],d[maxn],now[maxn],a[maxn],b[maxn],c[maxn];
int co[maxn];
int h[maxn],go[maxm*2],nex[maxm*2];
bool bz[maxn];
int i,j,k,w,l,t,n,m,K,tot,ca,T,mx;
bool czy;
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;
}
int random(int x){
    int t=rand()%10000;
    t=t*10000+rand()%10000;
    return t%x;
}
void add(int x,int y){
    d[y]++;
    go[++tot]=y;
    nex[tot]=h[x];
    h[x]=tot;
}
int main(){
    T=read();
    while (T--){
    n=read();m=read();K=read();
    //K++;
    tot=0;
    fo(i,1,n) d[i]=h[i]=0;
    fo(i,1,m){
        j=read();k=read();
        add(j,k);add(k,j);
    }
    fo(i,1,n) co[i]=0;
    mx=0;
    fo(i,1,n){
        t=h[i];
        while (t){
            bz[co[go[t]]]=1;
            t=nex[t];
        }
        bz[0]=1;
        co[i]=0;
        while (bz[co[i]]) co[i]++;
        mx=max(mx,co[i]);
        t=h[i];
        while (t){
            bz[co[go[t]]]=0;
            t=nex[t];
        }
    }
    if (mx<=K){
        printf("color ");
        fo(i,1,n) printf("%d ",co[i]);
        printf("\n");
    }
    else{
        printf("path ");
        fo(i,1,n)
            if (co[i]==K+1) break;
        j=i;
        printf("%d ",j);
        fd(i,K,1){
            t=h[j];
            while (t){
                if (co[go[t]]==i) break;
                t=nex[t];
            }
            j=go[t];
            printf("%d ",j);
        }
        printf("\n");
    }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值