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,其中

定义xy之间的距离。给定每个iTi之间的距离D(i,Ti),

你需要求出一个满足要求的变换序列T。如果有多个满足条件的序列,输出其中字典序最小的一个。

说明:对于两个变换序列ST,如果存在p<N,满足对于i=0,1,……p-1,Si=TiSp<Tp,我们称ST字典序小。

【输入文件】

输入文件transform.in的第一行包含一个整数N,表示序列的长度。接下来的一行包含N个整数Di,其中Di表示iTi之间的距离。

【输出文件】

输出文件为transform.out。

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

【输入样例】

5

1 1 2 2 1

【输出样例】

1 2 4 0 3

【数据规模和约定】

20%的数据中N≤50;

60%的数据中N≤500;

100%的数据中N≤10000。

题解:

二分图匹配+匈牙利算法

设原序列值为x[0],x[1],x[2]......x[n-1],要变成的序列值为y[0],y[1],y[2]......y[n-1].

原序列也就是0,1,2......n-1,即x[0]=0,x[1]=1,x[2]=2......x[n-1]=n-1.

首先,通过样例可以想到每一个值x[i]可以变成的 y[i]的取值最多只有两个,但为什么,证明如下:

设a=| x[i] - y[i] |,且a ≤ (n-a),其中a,(n-a)都为差值(由题目中可知)

对于每一个x[i],我们有y[i]=x[i]±a或y[i]=x[i]±(n-a).

因为每个x[i]和y[i]要满足0≤x[i]≤n-1,0≤y[i]≤n-1,且y[i]=x[i]±a或y[i]=x[i]±(n-a).

则可以得到:  x[i]+a≤n-1   --------------   (1)式

x[i]-a≥0       --------------   (2)式

x[i]+(n-a)≤n-1  ----------    (3)式

x[i]-(n-a)≥0   -------------   (4)式

(3)式化简可得 : x[i]-a≤-1

(4)式移项可得 : x[i]+a≥n

观察四个式子,我们可以发现 :(1)式 和 (4)式 是矛盾的,(2)式 和(3)式 是矛盾的.

所以,我们只能在 (1)式 和 (4)式 中选一个,(2)式 和(3)式 中选一个.

证毕.

然后,有了这个结论,我们就把题目变成了 :给出0...n-1,还给出了每个数的变化量(变化量给的是绝对值,也就是可以变化的差值),每个数都必须要 变化 且 恰好变化给定的差值 ,每个数可以变成两个数(上面已经证明),让你 变成0...n-1 且 使变后的序列 字典序 最小。

就可以跑匈牙利了(迷之时间复杂度。。。)

其实就是要判断是否 完美匹配 。若没有 完美匹配 ,则输出无解。

注意匈牙利要倒着跑,可以跑出 字典序 最小。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define MAXN 10010
 4 int BF[MAXN],BF1[MAXN],d[MAXN],prey[MAXN],n,f[MAXN][2];
 5 //bool f[MAXN][MAXN];
 6 bitset<MAXN> vis;
 7 int read()
 8 {
 9     int s=0,fh=1;char ch=getchar();
10     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)fh=-1;ch=getchar();}
11     while(ch>=‘0‘&&ch<=‘9‘){s=s*10+(ch-‘0‘);ch=getchar();}
12     return s*fh;
13 }
14 int Xyl(int u)
15 {
16     int i,v;
17     for(i=0;i<=1;i++)
18     {
19         v=f[u][i];
20         if(vis[v]==0)
21         {
22             vis[v]=1;
23             if(Xyl(BF[v])==1||BF[v]==0)
24             {
25                 BF[v]=u;
26                 BF1[u]=v;
27                 return 1;
28             }
29         }
30     }
31     return 0;
32 }
33 int main()
34 {
35     freopen("transform.in","r",stdin);
36     freopen("transform.out","w",stdout);
37     int i,ans,dd,gs;
38     n=read();
39     memset(f,false,sizeof(f));
40     for(i=0;i<n;i++)
41     {
42         d[i]=read();dd=n-d[i];
43         gs=-1;
44         if(i-d[i]>=0)f[i][++gs]=i-d[i];
45         if(i+d[i]<=n-1)f[i][++gs]=i+d[i];
46         if(i-dd>=0)f[i][++gs]=i-dd;
47         if(i+dd<=n-1)f[i][++gs]=i+dd;
48         if(f[i][0]>=f[i][1])swap(f[i][0],f[i][1]);
49     }
50     memset(BF,0,sizeof(BF));ans=0;
51     memset(prey,-1,sizeof(prey));
52     for(i=n-1;i>=0;i--)
53     {
54         vis.reset();
55         ans+=Xyl(i);
56         //prey[i]=BF1[i];
57     }
58     if(ans!=n)printf("No Answer");
59     else
60     {
61         //for(i=0;i<n;i++)BF1[BF[i]]=i;
62         for(i=0;i<n;i++)printf("%d ",BF1[i]);
63     }
64     fclose(stdin);
65     fclose(stdout);
66     return 0;
67 }
时间: 2024-10-25 05:37:59

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

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.

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,

匈牙利算法(二分图匹配)

#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; int n,m,k,ans,cnt,head[1001],vis[1001],match[1001]; struct uio{ int next,to; }edge[1000001

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的题目,果然是好题. 具

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

【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

【题解】 [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]\)

【bzoj1562】 NOI2009—变换序列

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

poj1274 匈牙利算法 二分图最大匹配

poj1274 题意: 有n个奶牛, m个畜舍, 每个畜舍最多装1头牛,每只奶牛只有在自己喜欢的畜舍里才能产奶. 求最大产奶量. 分析: 其实题意很明显, 二分图的最大匹配, 匈牙利算法. #include<iostream> #include<cstdio> #include<string.h> #include<cstring> using namespace std; int n, m, sum, v[210], ans[210], map1[210]