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

说明:对于两个变换序列\(S\)和\(T\),如果存在\(p<Np<N\),满足对于\(i=0,1,\cdots p-1\),\(S_i=T_i\)且\(S_p<T_p\),我们称\(S\)比\(T\)字典序小。

输入格式:

第一行包含一个整数\(N\),表示序列的长度。接下来的一行包含\(N\)个整数\(D_i\),其中\(D_i\)表示\(i\)和\(T_i\)之间的距离。

输出格式:

如果至少存在一个满足要求的变换序列\(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\)。


这个题目相当优秀,它能够很好的帮你理解匈牙利算法的本质。

首先看到这个题,可以很显然的发现这是一个裸的二分图匹配问题。但是牵涉到字典序最小的话,就需要考虑其他的操作了。

最开始我考虑的方法是从前到后匹配:

  • 如果两个都没有匹配,那么选数字小的那个
  • 如果都匹配了,选择如果匹配,会产生的影响最早数字最靠后的那个
  • 如果一个匹配一个没匹配,先选没匹配的那个

写了一堆特判之后WA成沙雕,还满的一批,因为我要在匹配之前提前模拟一遍第二种,然后就多了一堆奇奇怪怪的东西。

相比之下,正解的想法就相当有趣。

匈牙利算法本身就是从前向后依次尝试匹配。所以如果想要保证在前面的数字尽可能小,那么只需要让它优先匹配标号小的节点就好。但是这里存在一个问题:如果从前到后依次匹配的话,为了保证不把前面的最优选择替换,你就必须特判很多东西。实际上,只需要从后向前匹配,前面的尽可能选最小数字,如果可以替换,把后面选择的直接替换即可。这样得到的一定是最优解。

Code:

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 10010
#define _mod(x) ((x)%n+n)%n
using namespace std;
int n,T[MAXN],vis[MAXN<<1],v[MAXN][2],match[MAXN<<1]; bool dfs(int x){
// 寻找x的匹配
for(int i=0;i<2;++i){
if(!vis[n+v[x][i]]){
vis[n+v[x][i]]=true;
if(match[n+v[x][i]]==-1 || dfs(match[n+v[x][i]])){
match[x]=n+v[x][i];
match[n+v[x][i]]=x;
return true;
}
}
}
return false;
} int main(){
scanf("%d",&n);
memset(match,-1,sizeof(match));
for(int i=0;i<n;++i){
scanf("%d",&T[i]);
v[i][0]=_mod(i+T[i]);
v[i][1]=_mod(i-T[i]);
if(v[i][0]>v[i][1]){
swap(v[i][0],v[i][1]);
}
//临时储存两个终点
}
//按位匹配
for(int i=n-1;i>=0;--i){
memset(vis,0,sizeof(vis));
if(!dfs(i)){
puts("No Answer");
return 0;
}
}
for(int i=0;i<n;++i){
printf("%d ",match[i]-n);
}
}

P1963 [NOI2009]变换序列的更多相关文章

  1. Luogu P1963 [NOI2009]变换序列(二分图匹配)

    P1963 [NOI2009]变换序列 题意 题目描述 对于\(N\)个整数\(0,1, \cdots ,N-1\),一个变换序列\(T\)可以将\(i\)变成\(T_i\),其中\(T_i \in ...

  2. P1963 [NOI2009]变换序列 倒叙跑匈牙利算法

    题意 构造一个字典序最小的序列T,使得 Dis(i, Ti) = di,其中i是从0开始的,Dis(x,y)=min{∣x−y∣,N−∣x−y∣} ,di由题目给定. 思路 二分图匹配,把左边的看成i ...

  3. 洛谷 [P1963] [NOI2009] 变换序列

    这是一道二分图匹配的题 先%dalao博客 建图并没有什么难的,但是关键在于如何使字典序最小. 一个很显然的想法是先求出一个完美匹配,然后从x集合的第一个元素开始,如果该元素匹配的较小的一个,那么继续 ...

  4. 洛谷P1963 [NOI2009]变换序列(二分图)

    传送门 我可能真的只会网络流……二分图的题一点都做不来…… 首先每个位置有两种取值,所以建一个二分图,只要有完美匹配就说明有解 考虑一下每一个位置,分别让它选择两种取值,如果都不能形成完美匹配,说明无 ...

  5. Bzoj 1562: [NOI2009]变换序列 匈牙利算法,二分图匹配

    题目: http://cojs.tk/cogs/problem/problem.php?pid=409 409. [NOI2009]变换序列 ★★☆   输入文件:transform.in   输出文 ...

  6. BZOJ 1562 [NOI2009] 变换序列

    [NOI2009] 变换序列 [题解] 就是有一个序列,每个位置可以填两个数,不可重复,问最小字典序. 显然,可以建一个二分图,判合法就是找完美匹配. 那怎么弄最小字典序呢?有好多种解法,我这里给出了 ...

  7. [Luogu 1963] NOI2009 变换序列

    [Luogu 1963] NOI2009 变换序列 先%Dalao's Blog 什么?二分图匹配?这个确定可以建图? 「没有建不成图的图论题,只有你想不出的建模方法.」 建图相当玄学,不过理解大约也 ...

  8. noi2009变换序列

    noi2009变换序列 一.题目 1843 变换序列 2009年NOI全国竞赛  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解       题目描述  ...

  9. 【bzoj1562】 NOI2009—变换序列

    http://www.lydsy.com/JudgeOnline/problem.php?id=1562 (题目链接) 题意 给出一个序列(0~n-1),这个序列经过某个变换会成为另外一个序列,但是其 ...

随机推荐

  1. 领跑衫获奖感言 & 课程总结

    很荣幸在最后一次课获得了黄色领跑衫.在此,我要感谢教师杨贵福,感谢<构建之法>的作者邹欣老师和出版人周筠老师,感谢“耐撕”团队的队员们. 作为旁听生,最后一堂课,有些不舍.不多说,先上图, ...

  2. spring boot之mybatis配置

    配置在application.yml文件中 mybatis-plus: # 如果是放在src/main/java目录下 classpath:/com/yourpackage/*/mapper/*Map ...

  3. 安装Visual Studio 2013以及简单使用

    首先,在网上找到安装Visual Studio 2013的教程以及相关软件资源http://jingyan.baidu.com/article/09ea3ede3b2496c0afde3944.htm ...

  4. 读《移山之道——VSTS软件开发指南》

    读<移山之道>这本书差不多用了一个星期的时间,感觉还是收获了一些知识的,以前只是会简单地编个小程序(虽然现在也是这样),但看过这本书之后我对软件开发这个概念的认识度有了从一片模糊到了解大体 ...

  5. Linux内核分析期中总结

    目录: “Linux内核分析”实验一报告 “Linux内核分析”实验二报告 “Linux内核分析”实验三报告 Linux实验四报告 “Linux内核分析”第五周报告 "Linux内核分析&q ...

  6. 冲刺Two之站立会议9

    今天我们团队主要针对软件的功能进行了改进.因为它目前可以实现视频通话,语音聊天,文件传输和文字聊天的通信功能,我们想要在它的基础上实现临时局域群聊和群聊视频的功能,目前还没有完全实现.

  7. personal project

    words count program 统计文本文件的字符数,单词数和行数. 实现一个统计程序,他能正确的统计程序文件中的字符数,单词数和行数. 源码链接 https://github.com/sup ...

  8. github 心得体会

     https://github.com/xu123/text 学习了很多知识感觉很有趣 git config :配置git git add:更新working directory中的文件至stagin ...

  9. R和python语言如何求平均值,中位数和众数

    均值是通过取数值的总和并除以数据序列中的值的数量来计算. R语言平均值公式: mean(x, trim = 0, na.rm = FALSE, ...)#x - 是输入向量.trim - 用于从排序的 ...

  10. Fastdfs文件服务器搭建

    安装FastDFS之前,先安装libevent工具包.然后要安装libfastcommon和FastDFS,还要依赖nginx来显示图片. 1安装libevent yum -y install lib ...