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


    题目描述

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

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

    “势能法”是摊还分析中一种比较简单常用的方法,而且容易理解。现在零崎有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 }
     
  • 相关阅读:
    Mac 如何开启任何来源选项
    Fiddler抓包工具总结
    Inpaint>>一款神奇的去水印工具
    Adobe After Effects 2021 中文版 视频特效制作软件
    利用百度接口实现免费文字转语音
    普通电脑如何实现网吧锁屏?让你的电脑实现网吧挂机锁功能的方法
    一款强大的思维导图软件-XMind:ZEN 2020v10.0-免费安装与使用
    教你用 Python 修改微信(支付宝)运动步数,轻松升到 TOP1
    C# Winforn窗体的Load事件和Shown事件的区别
    判断输入的字符串是否是合法路径,并验证后面的输入是否含有非法字符
  • 原文地址:https://www.cnblogs.com/zpfbuaa/p/5002066.html
Copyright © 2020-2023  润新知