这道题算不算脑洞题。。
可以发现,当一个排列中有循环节时长度为1或2时可能有解。当为1时,只需把全部点都连到这个题即可,当为2时,就要求所有循环节长度均为偶数,这很容易理解,因为如果存在为奇数,它们之间连线之后就可以形成环或者不存在的情况了。把其他循环节上的点分别连到这两个点上即可。为什么是2呢?因为,可以理解为树上的一条连连T_T
666666
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; int permutations[100005]; bool vis[100005]; vector<int>ans; int main(){ int n; while(scanf("%d",&n)!=EOF){ for(int i=1;i<=n;i++){ scanf("%d",&permutations[i]); memset(vis,false,sizeof(vis)); } bool one_exist=false; bool two_exist=false; int two_pos=-1; int ans_one=-1; ans.clear(); for(int i=1;i<=n;i++){ if(!vis[i]){ int cc=1; vis[i]=true; int ni=i; while(!vis[permutations[ni]]){ ni=permutations[ni]; vis[ni]=true; cc++; } if(cc==1){ one_exist=true; ans_one=i; break; } if(cc==2){ two_exist=true; two_pos=i; } ans.push_back(cc); } } int sz=ans.size(); if(one_exist){ puts("YES"); for(int i=1;i<=n;i++){ if(i!=ans_one){ printf("%d %d\n",ans_one,i); } } continue; } if(two_exist){ bool flag=true; for(int i=0;i<sz;i++){ if(ans[i]%2!=0){ flag=false; break; } } if(flag){ puts("YES"); printf("%d %d\n",two_pos,permutations[two_pos]); vis[two_pos]=false; vis[permutations[two_pos]]=false; for(int i=1;i<=n;i++){ if(vis[i]){ int counts=0; vis[i]=false; int ni=i; printf("%d %d\n",two_pos,ni); while(vis[permutations[ni]]){ if(counts&1){ counts^=1; printf("%d %d\n",permutations[ni],two_pos); } else{ counts^=1; printf("%d %d\n",permutations[two_pos],permutations[ni]); } vis[permutations[ni]]=false; ni=permutations[ni]; } } } continue; } } puts("NO"); } return 0; }
时间: 2024-10-21 01:32:14