【题解】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 }