[AT2306]Rearranging(拓扑序)
题面(luogu):
有一个$n$个数组成的序列$a_{i}$。
高桥君会把整个序列任意排列,然后青木君可以选择两个相邻的互质的数交换位置。
高桥君希望最终序列的字典序尽量小,而青木君希望字典序尽量大。求最终序列。
思路:
经过一番思考,我们发现我们可以知道的只有“不互质的数之间不能交换”
换句话说也就是两个不互质的数之间的先后是不会反转的
但通过这个我们无法得到任何推论。。。
所以只能从这个唯一条件下手了。
考虑将不互质的数连未定向边
拓扑序就是这几个元素之间的相互顺序。
单个连通块里的处理:
找到连通块里最小的一个元素作为起点之后每次找相连的最小元素继续搜。
所以还请注意一下开始连边的枚举顺序。
多个连通块:
一个堆搞定。
#include<cstdio> #include<algorithm> #include<queue> #include<vector> using namespace std; const int N=2333; int a[N]; int g[N][N]; int n; int gcd(int a,int b){return b?gcd(b,a%b):a;} struct sumireko{int to,ne;}e[N*1000]; int he[N],ecnt; void addline(int f,int t) { e[++ecnt].to=t; e[ecnt].ne=he[f]; he[f]=ecnt; } bool vv[N]; int bi; int sp[N]; vector<int> to[N]; void dfs(int x) { vv[x]=1; for(int i=he[x],t;i;i=e[i].ne) { t=e[i].to; if(!vv[t]) { to[x].push_back(t); dfs(t); } } } priority_queue<int> q; int main() { freopen("rearranging.in","r",stdin); freopen("rearranging.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+1+n); for(int i=n;i;i--) for(int j=i-1;j;j--) if(gcd(a[i],a[j])!=1) addline(i,j),addline(j,i); for(int i=1;i<=n;i++) if(!vv[i]) { bi++; sp[bi]=i; dfs(i); } for(int i=1;i<=bi;i++) q.push(sp[i]); while(!q.empty()) { int g=q.top(); q.pop(); printf("%d ",a[g]); for(int i=0;i<to[g].size();i++) q.push(to[g][i]); } return 0; }