Codeforces Gym 100431A Achromatic Number 欧拉回路

原题链接:http://codeforces.com/gym/100431/attachments/download/2421/20092010-winter-petrozavodsk-camp-andrew-stankevich-contest-37-asc-37-en.pdf

题意

给你一个n,让你构造一个环,使得相邻的节点的颜色不一样,问最多能使用多少颜色,并且输出染色方案。

题解

首先,我们来考察对于k个颜色,我们至少需要多少节点。每个点可以连接两个点,将边考虑为有向边,如果我们不浪费任何一条边,对于一个颜色,我们将它连到其余的一半的颜色,将另外一半的颜色连接到他,由于可能除不尽,所以要向上取整。这样,我们得到了一个简单的公式,对于偶数的颜色k,我们需要k*k/2的点,对于奇数的颜色k,我们需要k*(k-1)/2的点。

现在反过来思考,对于给定的节点数,我们至少需要多少颜色。如果刚刚够用,自然最好,如若不然,就寻找一个合适的k,然后采取在多于的节点随便染色的策略。但事实并非如此,因为题意要求是个环,那么我们如若在最后补颜色,那么就会拆开最后一条边,所以,如果给的n只比合适值多1,那么颜色数就要减一,这就是为什么4个点的答案是2而3个点的答案是3。

接下来,我们来考虑如何构造解。对于我们已经构建好的有向图,本质上是要遍历所有的边。那么只需要在最初弄好的颜色的有向图上跑一发欧拉回路。然后我们需要填充多于的节点,为了避免出现拆开唯一的颜色边,所以应当将一个重复的边拆开,再在里面插点。插点时需要满足题意的条件。

此题坑非常多,需要十分细致,最好手算一下前10的答案,然后比对一下输出。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#define MAX_N 1234
using namespace std;

int gao[MAX_N];
int k;
struct edge
{
    bool vis;
    int to;
    edge(int t)
            :vis(0),to(t){}
    edge(){}
};

vector<edge> G[MAX_N];
int tot=0,road[MAX_N];
bool flag=false;
int n;

int st[MAX_N],all=0;

void dfs(int u) {
    //cout<<u<<endl;
    int i = gao[u];
    while (i < G[u].size() && G[u][i].vis)i++;
    if (i == G[u].size())return;
    gao[u] = i + 1;
    G[u][i].vis = 1;
    st[all++] = G[u][i].to;
    dfs(G[u][i].to);
}

bool check(int u) {
    //cout<<G[u][0].vis<<endl;
    if (gao[u] == G[u].size())return false;
    return true;
}

void Fluery(int s) {
    st[all++] = s;
    while (all) {
        int now = st[all - 1];
        if (check(now))dfs(now);
        else {
            //cout<<rHash(now)<<endl;
            road[tot++] = now;
            all--;
        }
    }
}

bool vis[MAX_N][MAX_N];
int newRoad[MAX_N];

int main() {
    freopen("achromatic.in","r",stdin);
    freopen("achromatic.out","w",stdout);
    scanf("%d", &n);
    for (k = 0; ; k++) {
        int t;
        if (k & 1)t = k * (k - 1) / 2;
        else t = k * k / 2;
        if (t > n)break;
    }
    k--;
    if ((k & 1) && n == (k * (k - 1)) / 2 + 1)k--;
    printf("%d
", k);
    for (int i = 0; i < k; i++)
        for (int j = 1; j <= k / 2; j++) {
            int u = i;
            int v = (i + j) % k;
            G[u].push_back(edge(v));
        }
    Fluery(0);
    int pos = 0;
    for (int i = 0; i < tot - 1; i++) {
        int u = i, v = (i + 1) % (tot - 1);
        if (vis[u][v]) {
            pos = u;
            break;
        }
        vis[u][v] = vis[v][u] = 1;
    }
    int nt = 0;
    for (int i = pos + 1; i < tot - 1; i++)
        newRoad[nt++] = road[i];
    for (int i = 0; i <= pos; i++)newRoad[nt++] = road[i];
    for (int i = 0; i < tot - 1; i++)
        printf("%d ", newRoad[i] + 1);
    if (n == tot - 1) { return 0; }
    if (n - (tot - 1) == 1) {
        int j = 1;
        while (j == newRoad[tot - 2] + 1 || j == newRoad[0] + 1) {
            j++;
            if (j == k + 1)j = 1;
        }
        printf("%d
", j);
        return 0;
    }
    printf("%d ", newRoad[0] + 1);
    int p = newRoad[0] + 1;
    for (int i = tot; i < n; i++) {
        int j = 1;
        while (j == p || (i == n - 1 && j == newRoad[0] + 1)) {
            j++;
            if (j == k + 1)j = 1;
        }
        printf("%d ", j);
        p = j;
    }
    printf("
");
    return 0;
}
原文地址:https://www.cnblogs.com/HarryGuo2012/p/4737555.html