[NOI2009]变换序列 题解

[NOI2009]变换序列 题解

题目地址:洛谷:【P1963】[NOI2009]变换序列 – 洛谷、BZOJ:Problem 1562. — [NOI2009]变换序列

题目描述

对于 N 个整数 0,1,⋯,N-1 ,一个变换序列 T 可以将 i 变成 Ti ,其中 Ti∈{0,1,⋯,N−1} 且 \bigcup_{i=0}^{N-1} \{T_i\} = \{0,1,\cdots , N-1\} 。 , ∀x,y∈{0,1,⋯,N-1} ,定义x和y之间的距离 D(x,y)=min{|x-y|,N-|x-y|} 。给定每个 i 和 Ti 之间的距离 D(i,Ti) ,你需要求出一个满足要求的变换序列T。如果有多个满足条件的序列,输出其中字典序最小的一个。

说明:对于两个变换序列 S 和 T ,如果存在 p<N ,满足对于 i=0,1,⋯p-1 , Si=Ti 且 Sp<Tp ,我们称 S 比 T 字典序小。

输入输出格式

输入格式:
第一行包含一个整数 N ,表示序列的长度。接下来的一行包含 N 个整数 Di ,其中 Di 表示 i 和 Ti 之间的距离。

输出格式:
如果至少存在一个满足要求的变换序列 T ,则输出文件中包含一行 N 个整数,表示你计算得到的字典序最小的 T ;否则输出No Answer(不含引号)。注意:输出文件中相邻两个数之间用一个空格分开,行末不包含多余空格。

输入输出样例

输入样例#1:

5
1 1 2 2 1

输出样例#1:

1 2 4 0 3

说明

对于30%的数据,满足:N<=50;
对于60%的数据,满足:N<=500;
对于100%的数据,满足:N<=10000。

题解

从i向可能的Di连有向边,其实是个二分图匹配,如果匹配不够n,则无解。有解要求输出字典序最小的答案,这需要一些思考。匈牙利算法的流程中,实际上是按顺序扩展增广路上点的集合的,因此如果倒序求增广路,可能更小的点会替代原来匹配上的更大的点,然后再把每个点的出边表从小到大排个序,就可以实现字典序最小。

代码

// Code by KSkun, 2018/5
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>
#include <vector>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1;
    register char c = fgc();
    while(!isdigit(c)) {
        if(c == '-') neg = -1;
        c = fgc();
    }
    while(isdigit(c)) {
        res = (res << 1) + (res << 3) + c - '0';
        c = fgc();
    }
    return res * neg;
}

const int MAXN = 20005;

int n;

std::vector<int> gra[MAXN];

int match[MAXN];
bool vis[MAXN];

inline bool dfs(int u) {
    for(int i = 0; i < gra[u].size(); i++) {
        int v = gra[u][i];
        if(!vis[v]) {
            vis[v] = true;
            if(match[v] == -1 || dfs(match[v])) {
                match[v] = u; match[u] = v; return true;
            }
        }
    }
    return false;
}

inline int bmatch() {
    int res = 0;
    memset(match, -1, sizeof(match));
    for(int i = n - 1; i >= 0; i--) {
        if(match[i] == -1) {
            memset(vis, 0, sizeof(vis));
            if(dfs(i)) res++;
        }
    }
    return res;
}

int d[MAXN];

int main() {
    n = readint();
    for(int i = 0; i < n; i++) {
        d[i] = readint();
    }
    for(int i = 0; i < n; i++) {
        gra[i].push_back((i + d[i]) % n + n);
        gra[i].push_back((i - d[i] + n) % n + n);
    }
    for(int i = 0; i < n << 1; i++) {
        std::sort(gra[i].begin(), gra[i].end());
    }
    if(bmatch() < n) {
        puts("No Answer");
    } else {
        for(int i = 0; i < n; i++) {
            printf("%d ", match[i] - n);
        }
    }
    return 0;
}


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据