机智零崎不会没梗Ⅲ (摊还分析)

题目描述

零崎总是说自己有一百种梗可玩,然而其实都是假的,是化学成分的,是特技。想要给摊还分析加个梗,实在是不好想,因为这个内容并不是什么算法,而是算法分析。

不过既然还得考,那么没有办法……

“势能法”是摊还分析中一种比较简单常用的方法,而且容易理解。现在零崎有K个硬币,规定每次“翻动”操作只能从最右侧开始翻转硬币,且如果把一个硬币从正面向上翻到背面向上,则需要对其左侧相邻的那个硬币也执行“翻动”操作(翻至最左则结束)。定义硬币组的势为硬币中正面向上的硬币的个数。现在要求你求出从某个给定的硬币组状态之后连续N个“翻动”操作的摊还代价。

硬币组的初始状态以一组数表示,0代表反面,1代表正面。

输入

多组测试数据。

每组测试数据共两行:

第一行K+1个正整数,分别为硬币组中硬币数K和初始状态(0<K<20);

第二行一个正整数,为题目要求你求出的“翻动”操作的个数N(0<N<30)。

输出

每组测试数据输出一行,此行第i个数输出初始状态后第i个操作的摊还代价(1<=i<=N)。

输入样例

3 0 0 0
2

输出样例

2 2

题目来源:http://biancheng.love/contest/23/problem/F/index
所谓摊还分析:求数据结构中的一个操作序列中所执行的所有操作的平均时间,来评价操作的代价。我们可以说明一个操作的平均代价很低,即使序列中某个单一操作的代价很高。瘫痪分析不同于平均情况分析,它不涉及到概率问题,它可以保证最坏的情况下每个操作的平均性能。
解题思路:在计算摊还代价时可以采用:聚合分析、核算法、势能算法。参考算法导论书中的例子:二进制计数器递增问题。通过题目要求可以得到,反转硬币其实也就是实现二进制计数器的递增问题,在摊还代价计算中得到如果反转到全为0,摊还代价为0,其他情况均为1,因此可以采用简单粗暴的方法。计算对应二进制的十进制数,由于反转硬币的摊还代价是有周期的(在给定二进制位数之后,周期为2^k);因此只需要判断是输出0还是输出2就可以了。
本题代码:

 1 #include <bits/stdc++.h>
 2 #define max_size  21
 3 int a[max_size];
 4 using namespace std;
 5 int main()
 6 {
 7     int k,num,flag,N;
 8     while(~scanf("%d",&k))
 9     {
10         num=0;
11         flag=pow(2,k);
12         for(int i=1;i<=k;i++)
13             scanf("%d",&a[i]);
14         for(int i=1;i<=k;i++)
15             num+=a[i]*pow(2,k-i);
16         scanf("%d",&N);
17         int temp=flag-num;
18         for(int i=1;i<=N;i++)
19         {
20             if(i<=temp-1)
21             {
22                 if((i-1)==temp)
23                     printf("0 ");
24                 else
25                     printf("2 ");
26             }
27             else if(i>=temp)
28             {
29                 if((i+num)%flag==0)
30                     printf("0 ");
31                 else
32                     printf("2 ");
33             }
34         }
35         printf("
");
36     }
37 }

采用判断是否所有位数都为0,来进行输出的另外一种方法:

 1 #include<iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int N;
 6     while(cin>>N)
 7     {
 8         int A[N],k;
 9         for(int i=0; i<N; i++)
10         {
11             cin>>A[i];
12         }
13         cin>>k;
14         int j=N-1;
15         for(int i=1; i<=k; i++)
16         {
17             while(j>=0 && A[j]==1)
18             {
19                 A[j]=0;
20                 j--;
21             }
22             if(j>=0)
23             {
24                 A[j]=1;
25                 cout<<"2 ";
26             }
27             else
28             {
29                 for(int k=0; k<N; k++)
30                     A[k]=0;
31                 cout<<"0 ";
32             }
33             j=N-1;
34         }
35         cout<<endl;
36     }
37 }
 
原文地址:https://www.cnblogs.com/zpfbuaa/p/5002066.html