【题解】Luogu P1963 [NOI2009] 变换队列 二分图

首先得读懂题......

题意:给你$n$对数的位置关系,问怎样使这个排列满足要求且字典序最小

好像还不是人话 

就是说对于$0~n-1$,每个${i}$对应两个位置上的数,问上面那个问题

有对应关系求小字典序,可以转化为倒着跑匈牙利求最大匹配

注意编号从${0}$开始,建边的时候先建大的再建小的,因为要倒着做

code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int mod=1e9+7;
 5 const int maxn=1e5+10;
 6 namespace gengyf{
 7 inline int read(){
 8     int x=0,f=1;char s=getchar();
 9     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
10     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
11     return f*x;
12 }
13 int n,a[maxn],ans;
14 struct edge{
15     int nxt,to;
16 }e[maxn<<1];
17 int head[maxn],cnt,match[maxn],vis[maxn],to[maxn];
18 inline void add(int from,int to){
19     e[++cnt].to=to;e[cnt].nxt=head[from];head[from]=cnt;
20 }
21 bool dfs(int x){
22     for(int i=head[x];i;i=e[i].nxt){
23         int y=e[i].to;
24         if(vis[y])continue;
25         vis[y]=1;
26         if(!match[y]||dfs(match[y])){
27             match[y]=x;to[x]=y;return 1;
28         }
29     }
30     return 0;
31 }
32 int main(){
33     n=read();
34     for(int i=0;i<n;i++){
35         a[i]=read();
36         int x=(i-a[i]+n)%n;
37         int y=(i+a[i])%n;
38         add(i,max(x,y));add(i,min(x,y));
39     }
40     for(int i=n-1;i>=0;i--){
41         memset(vis,0,sizeof(vis));
42         if(dfs(i))ans++;
43     }
44     if(ans<n){
45         puts("No Answer");return 0;
46     }
47     for(int i=0;i<n;i++){
48         if(i==n-1)printf("%d",to[i]);
49         else printf("%d ",to[i]);
50     }
51     return 0;
52 }
53 /*
54  affection 挚爱
55  adopt 采纳
56  administration 管理
57  agent 代理
58 */
59 }
60 signed main(){
61     gengyf::main();
62     return 0;
63 }
View Code

 

posted @ 2019-10-28 09:25  喵の耳  阅读(129)  评论(0编辑  收藏  举报