noi2009变换序列

noi2009变换序列

一、题目

1843 变换序列

2009年NOI全国竞赛

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 大师 Master

题解

题目描述 Description

对于N个整数0,1,…,N-1,一个变换序列T可以将i变成Ti,其中:Ti∈{0,1,…,N-1}且Ui=1 to n-1 {Ti}={0,1,…,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,&hellip;,p-1,Si=Ti且Sp<Tp,我们称S比T字典序小。

输入描述 Input Description

输入文件中的第一行为一个整数N,表示序列的长度。

接下来的一行为N个整数Di,其中:Di表示i和Ti之间的距离。

输出描述 Output Description

如果至少存在一个满足要求的变换序列T,则输出一行为N个整数,表示你计算得到的字典序最小的T;否则输出&ldquo;No Answer&rdquo;(不含引号)。

输出文件中相邻两个数字之间用一个空格分开,行末不包含多余空格。

样例输入 Sample Input

5

1 1 2 2 1

样例输出 Sample Output

1 2 4 0 3

数据范围及提示 Data Size & Hint

对于30%的数据,满足:N<=50;

对于60%的数据,满足:N<=500;

对于100%的数据,满足:N<=10000。

分类标签 Tags 点此展开

大陆地区 NOI全国竞赛 2009年

二、分析

1、题目描述:

我现在简要述说一下这一题的意思:题目的意思就是给出x对y的对应关系:,现在给出D(x,y)和x,求y,并且要求字典序最小的y。(x这组数是从0到n-1,y这组数属于0到n-1)

下面分析一下样例就更加方便理解这个题目了:


X


0


1


2


3


4


D(x,y)


1


1


2


2


1


Y


1


2


4


0


3

表一

样例输入中给了n为5,,所以表一第一行x的值也是从0到4。表一的第二行D(x,y)就是输入数据的x,y的关系。最后需要我们求的就是表一第三行的y的数据。

我们可以看到上表中的(每列)每组x,y,D(x,y)都是满足关系,比如x=0,D(x,y)=1,y=1这一列,

|x-y|=1,N-|x-y|=4,故D(x,y)=1,所以关系成立,后面的以此类推。

2、题目思考:

我们在仔细来看一下关系式,发现对于这样的一个关系式,我们知道D(x,y)和x,求y的话,y最多有四个值,不过其实仔细拿实例出来分析之后,就发现这四个值是可以变成两个值的。

看到题目,发现题目是一个赤裸裸的二分匹配。这个题目可以用匈牙利算法来做,匈牙利算法的时间复杂度是O(nm),在这里是完全ok的。

这个题目还有另外一个难点,就是要求字典序最小的y,其实求最小的y可以在寻找交错路(匹配关系)的时候倒序寻找,不过这样做的时候要注意,在存边关系的连接表的时候要注意从小往大存,确保从字典序小的边找起。

因为如果正序查找,按照匈牙利算法的算法规则,那么一定是找到的字典序最大的那个。

问题:求二分图最大匹配可以用最大流(Maximal Flow)或者匈牙利算法(Hungarian Algorithm)

3、总结:

总结:其实这个题目就是二分匹配中的匈牙利算法,套用下匈牙利的模板,再想好怎么输出字典序最小的y就ok了。

三、代码

 1 #include<iostream>
 2 #include<iomanip>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<algorithm>
 8 #include<queue>
 9 #include<map>
10 #define MAXN 10010
11 using namespace std;
12
13
14
15 int graph[MAXN][2];//每个点最多连出2条边,存边时保证graph[i][0]
16
17 int vis[MAXN];//表示节点是否被访问
18 int match[MAXN];//Y集合中的点i与X集合的match[i]匹配
19 int ans[MAXN];//用于输出结果
20 int n;
21
22 //用来构建关系,确保字典序小的存在前面
23 void addedge(int i,int ver)
24 {
25    if(graph[i][0]<0)
26    {
27        graph[i][0]=ver;
28        return;
29    }
30    else if(graph[i][0]>ver)
31         {
32            graph[i][1]=graph[i][0];
33            graph[i][0]=ver;
34         }
35         else graph[i][1]=ver;
36 }
37 //匈牙利算法中的寻找交错路
38 bool crosspath(int ns)
39 {
40    int j,nt;
41    for(j=0;j<=1;j++)//每个点优先匹配编号较小的点(graph[i][0]
42    {
43        nt=graph[ns][j]; if(nt<0) continue;
44        if(vis[nt]) continue;
45        vis[nt]=1;
46        if(match[nt]<0||crosspath(match[nt]))
47        {
48            match[nt]=ns;
49            return true;
50        }
51    }
52    return false;
53 }
54 //匈牙利算法倒叙从每个点找交错路,确保求出最小字典序y
55 int find()
56 {
57    memset(match,128,sizeof(match));
58    memset(vis,0,sizeof(vis));
59    int i,tot=0;
60    for(i=n-1;i>=0;i--)//倒叙从每个点找交错路
61    {
62        if(crosspath(i)) tot++;
63        memset(vis,0,sizeof(vis));
64    }
65    return tot;
66 }
67
68
69
70 int main()
71 {
72     //freopen("in.txt","r",stdin);
73     //输入数据以及确定每个D(x,y)和x对应的y,用于构造二分图
74     int i,qh,l,r;
75     scanf("%d",&n);
76     memset(graph,128,sizeof(graph));
77     for(i=0;i<n;i++)
78     {
79        scanf("%d",&qh);//qh为读入的d[i],从i向i+d[i],i-d[i]连边(要取模)
80        l=((i-qh)%n+n)%n;
81        r=((i+qh)%n+n)%n;
82        addedge(i,l);
83        if(r!=l) addedge(i,r);
84     }
85     if(find()<n)//未能完全匹配则无解。
86     {
87        printf("No Answer");
88        exit(0);
89     }
90     //统计答案输出。
91     for(int i=0;i<n;i++) ans[match[i]]=i;
92     printf("%d",ans[0]);
93     for(int i=1;i<n;i++) printf(" %d",ans[i]);
94     return 0;
95 }
时间: 2024-10-19 10:58:18

noi2009变换序列的相关文章

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

题目: http://cojs.tk/cogs/problem/problem.php?pid=409 409. [NOI2009]变换序列 ★★☆   输入文件:transform.in   输出文件:transform.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 对于N个整数0, 1, ……, N-1,一个变换序列T可以将i变成Ti,其中 定义x和y之间的距离.给定每个i和Ti之间的距离D(i,Ti), 你需要求出一个满足要求的变换序列T.如果有多个满足条

BZOJ1562: [NOI2009]变换序列

1562: [NOI2009]变换序列 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1148  Solved: 599[Submit][Status] Description Input Output Sample Input 5 1 1 2 2 1 Sample Output 1 2 4 0 3 HINT 30%的数据中N≤50:60%的数据中N≤500:100%的数据中N≤10000. Source 题解: 不愧是NOI的题目,果然是好题. 具

【bzoj1562】 NOI2009—变换序列

http://www.lydsy.com/JudgeOnline/problem.php?id=1562 (题目链接) 题意:给出一个序列(0~n-1),这个序列经过某个变换会成为另外一个序列,但是其中的元素不会改变,给出初始序列与变换后的序列每一位上的“距离”,求字典序最小的变换序列. Solution  每个位置上只有2种情况,很明显的二分图匹配.因为要求字典序最小,我们考虑匈牙利算法的运行方式,是保证当前匹配的点最优,所以连边是将字典序小的点尽可能后连,保证第一个邻接表第一个选出来的点事字

【BZOJ1562】【jzyzOJ1730】【COGS409】NOI2009变换序列 二分图匹配

[问题描述] 对于N个整数0, 1, --, N-1,一个变换序列T可以将i变成Ti,其中 定义x和y之间的距离.给定每个i和Ti之间的距离D(i,Ti), 你需要求出一个满足要求的变换序列T.如果有多个满足条件的序列,输出其中字典序最小的一个. 说明:对于两个变换序列S和T,如果存在p<N,满足对于i=0,1,--p-1,Si=Ti且Sp<Tp,我们称S比T字典序小. [输入文件] 输入文件transform.in的第一行包含一个整数N,表示序列的长度.接下来的一行包含N个整数Di,其中Di

1562: [NOI2009]变换序列 - BZOJ

Description Input Output Sample Input 5 1 1 2 2 1 Sample Output 1 2 4 0 3 HINT 30%的数据中N≤50:60%的数据中N≤500:100%的数据中N≤10000. 二分图匹配,倒着匹配,每次选小的增广(随便乱yy一下,应该就可以证明是字典序最小的吧) 1 const 2 maxn=10010; 3 var 4 first,link:array[0..maxn]of longint; 5 a:array[0..maxn,

[luoguP1963] [NOI2009]变换序列(二分图最大匹配)

传送门 根据公式xjb推一下,然后就可以连边. 考虑到字典序最小,和匈牙利算法的实现过程,要倒序匹配. #include <cmath> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define N 40001 using namespace std; int n, cnt; int h

BZOJ 1562 [NOI2009]变换序列:二分图匹配

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1562 题意: 给定n,定义D(x,y) =  min(|x-y|, n-|x-y|),然后给定数组d[i] = D(i,T[i]). 让你求一个0到n-1的排列T,下标i∈[0,n-1],满足给定的D(i,T[i]),且字典序最小. 若没有答案输出"No Answer". 题解: 其实就是让你求一个排列T,其中T[i]要么填(i+d[i])%n,要么填(i-d[i]+n)%n.

【题解】 [NOI2009]变换序列 (二分图匹配)

懒得复制,戳我戳我 Solution: 这个题面出的很毒瘤,读懂了其实是个板子题qwq 题面意思:有个\(0\)至\(N-1\)的数列是由另一个数列通过加减得到的,相当于将\(A_i\)变成\(i\),每一步的代价计算就是\(min(A_i-i,N-(A_i-i))\),并且\(A_i\left(0<=i<N\right)\)互不相同,读入代价,要求字典序最小的满足要求的数列 我们设读入的为\(w[i]\) 思路其实很简单,\(i\)只可能是由\(i-w[i]\) 或者 \(i+w[i]\)

bzoj 1000+AC

1500 [NOI2005]维修数列   5333 16036 1010 [HNOI2008]玩具装箱toy   5205 12140 2049 [Sdoi2008]Cave 洞穴勘测   4992 10282 1008 [HNOI2008]越狱   4820 11120 1503 [NOI2004]郁闷的出纳员   4629 12915 1208 [HNOI2004]宠物收养所   4216 10462 1026 [SCOI2009]windy数   4169 9168 1003 [ZJOI2