poj2166 Heapsort[构造递推]

构造一个n个点的大根堆让全部弹出时交换位置次数最多。


真心佩服我自己智商,这种傻*题都做不出来


交换是在每次弹出堆顶,然后把堆尾元素置于堆顶,然后向下调整时产生的。玩样例可以发现似乎数字1每次都出现在堆最底层最右边(堆尾)?于是为了总交换数最多,肯定是要1号自顶向下交换到底次数最多,除此之外还希望它每次都跑到堆尾,这样是肯定最多的。观看堆的工作过程,发现构造出来的堆每弹出一个调整之后得到的$n-1$个元素的堆还是符合要求的,也就是说$n$个元素的答案堆可变为$n-1$元素的答案堆,于是可以从$n-1$个递推,具体过程是把弹出后调整的过程倒过来做,原来是沿顶向底路径都向上提一层(1与之交换所得),那递推就是路径每一点向下一层,1号点放$n$,$n$号点放$1$。画图很容易理解。

我    好    菜    啊

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define dbg(x) cerr<<#x<<" = "<<x<<endl
 8 #define _dbg(x,y) cerr<<#x<<" = "<<x<<"   "<<#y<<" = "<<y<<endl
 9 using namespace std;
10 typedef long long ll;
11 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
12 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
15 template<typename T>inline T read(T&x){
16     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
17     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
18 }
19 char F[200];int cnt;
20 inline void Write(int x){
21     cnt=0;
22     while(x)F[++cnt]=x%10+'0',x/=10;
23     while(cnt)putchar(F[cnt--]);
24     putchar(' ');
25 }
26 const int N=5e4+7;
27 int a[N];
28 int n;
29 
30 int main(){//freopen("test.in","r",stdin);//freopen("test.out","w",stdout);
31     read(n);a[1]=1;
32     for(register int i=2,x;i<=n;++i){
33         x=i-1;
34         while(x^1)a[x]=a[x>>1],x>>=1;
35         a[1]=i,a[i]=1;
36     }
37     for(register int i=1;i<=n;++i)Write(a[i]);
38     return printf("\n"),0;
39 }

猜你喜欢

转载自www.cnblogs.com/saigyouji-yuyuko/p/11450565.html