4878: [Lydsy2017年5月月赛]挑战NP-Hard

4878: [Lydsy2017年5月月赛]挑战NP-Hard

Time Limit: 1 Sec Memory Limit: 256 MBSec Special Judge
Submit: 360 Solved: 110
[Submit][Status][Discuss]
Description

天才大学生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知道你没有他的水平,所以你只需解决上面
的任意一个问题就可以成为他的粉丝。
Input

第一行包含一个正整数T(1<=T<=1000),表示测试数据的组数。
对于每组数据,第一行包含三个正整数n,m,k(1<=n<=1000,1<=m<=10000,1<=k<=n),分别表示图的点数与边数。
接下来m行,每行两个正整数a,b(1<=a,b<=n),表示a到b之间存在一条无向边。
输入数据保证不存在重边与自环,且总边数不超过100000。
Output

对于每组数据:
若选择了图染色问题,请输出“color”,然后输出n个在1到k之间的正整数,分别表示每个点的颜色。
若选择了简单路径问题,请输出“path”,然后输出k+1个在1到n之间的正整数,分别表示路径上每个点的编号。
若有多组可行解,输出任意一组。
Sample Input

2

4 5 2

1 2

2 3

3 4

4 1

1 3

3 3 3

1 2

2 3

3 1
Sample Output

path 3 2 1

color 1 2 3

HINT

Source

鸣谢Claris上传试题

[Submit][Status][Discuss]

思路十分巧妙的题。。。看了题解以后懊悔无比
众所周知,两个子问题都是NP-HARD
但是我们可以把它们拼在一起。。。。。。
先给这张图随机染色
即对于每个节点,将所有和它相邻的已经染色的点取 mex 当做这个点的颜色
这样做当然很可能分分钟爆 k 的限制
但是一旦超过这个限制
任意找一个颜色为k+1的点
每次找颜色标号比它小 1 的点,就能解决第二问了
因为是取mex的,所以这样的点一定存在

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define max(a,b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 1005;

int n,m,k,T,cnt,c[N],nex[N],a[N],vis[N];

vector <int> v[N];

inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}

inline void Clear()
{
    for (int i = 1; i <= n; i++) nex[i] = c[i] = 0,v[i].clear();
}

char s[20];
inline void Print(int x)
{
    int len = 0;
    while (x) s[++len] = x % 10,x /= 10;
    for (int i = len; i; i--) putchar(s[i] + '0');
}

inline void Solve()
{
    int Max = 0; n = getint(); m = getint(); k = getint();
    while (m--)
    {
        int x = getint(),y = getint();
        v[x].push_back(y); v[y].push_back(x);
    }
    for (int i = 1; i <= n; i++)
    {
        ++cnt;
        for (int j = 0; j < v[i].size(); j++)
        {
            int to = v[i][j];
            vis[c[to]] = cnt; a[c[to]] = to;
        }
        for (int j = 1; ; j++)
            if (vis[j] != cnt) {c[i] = j; break;}
        Max = max(Max,c[i]);
        if (c[i] > 1) nex[i] = a[c[i] - 1];
    }
    if (Max <= k)
    {
        printf("color ");
        for (int i = 1; i <= n; i++) Print(c[i]),putchar(i < n ? ' ' : '\n');
    }
    else
    {
        printf("path "); int s;
        for (int i = 1; i <= n; i++) if (c[i] == k + 1) {s = i; break;}
        for (int i = s; i; i = nex[i])
            Print(i),putchar(nex[i] ? ' ' : '\n');
    }
}

int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif

    T = getint();
    while (T--) Solve(),Clear();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值