zoukankan      html  css  js  c++  java
  • 《算法艺术与信息学竞赛》读书笔记一

    1.有这样一道题目:用1、2、3、4、5、6、7、8、9九个数字拼成一个九位数(每个数字恰好用一次),使得它的前三位、中间三位、最后三位的比值是1 : 2 : 3。例如192384576就是一个合法的解,因为192 : 384 : 576 = 1 : 2 : 3。

    #include <iostream >
    using namespace std;
    
    int main()
    {
        int i, x, y, z;
        int d[9]= {1, 2, 3, 4, 5, 6, 7, 8, 9};
        do{
            x = d[0] * 100 + d[1] * 10 + d[2];
            y = d[3] * 100 + d[4] * 10 + d[5];
            z = d[6] * 100 + d[7] * 10 + d[8];
            if(y == x * 2 && z == x * 3)
                cout << x << y << z << endl;
        }while(next_permutation(d, d + 9));
        return 0;
    }
    

    顺便说一句,答案有四个:192384576、219438657、273546819、327654981。这个例子告诉我们:计算机和人相比有速度优势。

    2.人为什么要在合上书之前夹一枚书签?听课时为什么要做笔记?都是避免把曾经记住的东西忘掉。\记忆"分成两部分,用计算机术语来说,\记"是写(write),\忆"是读(read)。

      只要你的内存足够大,任意大(注意,不是无穷大)的整数都可以保存。

      分形:部分和整体相似。 

      PostScript(PS)是主要用于电子产业和桌面出版领域的一种页面描述语言和编程语言。 PostScript是Adobe公司开发的一种设备无关的打印机程序语言,用来驱动数字印刷机和显示。

      除以2可以用移位实现,这样更快。

      判断所有数是否全部相同?

      A.逐一判断a[0]和后边的元素是否相同

      B.

    #include <iostream >
    #include <vector >
    using namespace std;
    typedef vector <int > vi;
    bool all_same(vi v)
    {
    for(int i = 0; i < v.size() - 1; i++
    if(v[i] != v[i+1]) return false;
    return true;
    }
    int main()
    {
    vi v;
    int i;
    while(cin >> i)
    v.push_back(i);
    cout << all_same(v);
    return 0;
    }
    

    3.线性时间算法:输入规模增加一倍,则运行时间约扩大一倍。也称O(n)时间算法。

    判断n个数是否两两不相同?(O(nlogn))

    bool solve(int a[],int n)
    {
    for(i=0; i<n-1; i++)
        for(j=i+1; j<n; j++)
        if(a[i]==a[j])
            return false;
        return true;
    }
    

     4.大多数实际问题涉及到的因素很多,在求解之前必须经过简化,得到问题的原型(prototype)。这个原型应当是没有歧义的。

    //freopen
    #include <iostream >
    #include <fstream >
    using namespace std;
    
    ifstream fin("sum.in");
    ofstream fout("sum.out");
    
    int main()
    {
        int a, b;
        fin >> a >> b;
        fout << a + b << endl;
        return 0;
    }
    

    5.不要写编译器相关的代码!它们是有二义的。

    地址空间是线性的并不代表内存物的理结构也是线性的。

    int最大值比2.1*10^9大一些。

    6.二叉树可以采用链式存储也可以采用数组存储,采用数组存储根据任一节点i的父节点是i/2,左右儿子分别是2*i和2i+1。至于一般意义下的树(每个结点可以有多个儿子,而且各个儿子之间也没有顺序关系),可以转化成二叉树存储。在新的二叉树中,每个结点的左儿子为原树中的第一个儿子,右儿子为原树中的下一个兄弟。这样的表示法称为左儿子-右兄弟表示法(left child-right sibling representation) ,它相当于把所有儿子串成了一个链表。

    图有两种常用的表示法:邻接矩阵(adjacency matrix) 和邻接表(adjacency list)。邻接矩阵的主要缺点是空间占用大。

    7.有一只自动储钱罐,它有一个孔和一个按钮。存钱的时候,你可以从小孔往里面投一枚硬币;取钱的时候,只要按一下按钮,面值最大的硬币就会从孔里掉出来。小机器人是这样工作的:当你扔一枚硬币进来的时候,它什么都不做,自己睡大觉;当你按按钮的时候,它慌了,赶紧找钱。它先随便挑出一个硬币拿在手里,然后把其他所有硬币的看一遍,如果发现更值钱的,就用把手里的硬币换掉,最后手里拿着的就是最值钱的硬币,然后从孔里扔出去。

    void new_coin ()
    {
     zzzZZZ ();
    }
    void delete_max ()
    {
        int i;
        int best = 0;
        for(i = 1; i < coin_count ; i ++)
              if( coin [i] > coin [ best ]) 
                  best = i;
        throw_away ( best );
    }
    

    我们把这种方法称为无序数组实现法。

    可以预料,这个钱罐\添加硬币"很快(小机器人啥都不做),找最大面值却很慢。如果小机器人检查一枚硬币的时间是0.01秒,那么有100个硬币时需要1秒,有10,000个硬币时需要100秒( 约两分钟) , 而1,000,000个硬币时就需要10,000秒(约2.8小时)!你可以忍受这样的速度吗?如果改改小机器人的程序,情况就完全不一样了!如果你曾留意过超市里的售货员是怎样找零钱的,你也立刻明白这个方案:拿几个不同的小桶,每个桶装一种面值的硬币。假设一共有1元、5角、1角、5分、2分和1分共6种面值的硬币,则只需要六个桶。当来了一枚新硬币时,小机器人把它放到相应的盒子中;需要找钱时,小机器人只需要看1元的盒子里有没有硬币,有的话随便拿一个扔出去;如果没有的话再看5角的盒子有没有硬币,有的话随便拿一个扔出去⋯不管有多少硬币,只要盒子装得下,总是最多只需要开6次桶即可,即使每开一个桶需要5秒钟,有1,000,000个硬币时最多也只需要半分钟,比刚才的2.8小时快多了。

    void new_coin (int value )
    {
        count [ value ]++;
    }
    void delete_max ()
    {
        int i;
        for(i = 1; i <= 6; i ++)
            if( count [i ] > 0) 
                throw_away (i);
    }
    

     这个方法虽然好,但是前提是只有6种面值。如果1分、2分、3分、4分、. . .99元9角8分、99元9角9分、100元整这1万种面值的硬币都有,那就需要1万个盒子。如果扔的1,000,000个硬币的面值全部不同,那么这个新方法就没有任何优势了。讲了这么多,只是想说明一个问题:相同的外特性(自动储钱罐)可以用多种结构(小机器人的程序)实现,它们的时间效率可能不同,空间开销也可能不同(新程序需要用附加盒子)。事实上,存在一个更好的结构来实现这个储钱罐,它就是原书中介绍的堆实现法。不管面值有多少种,在有1,000,000个硬币的情况下也最多只需要不到一秒钟。

    8.抽象数据类型(Abstract Data Types, ADT) 是只通过接口访问的数据类型(数据类型是指值集合和值上的操作集合)。使用ADT的程序叫客户端(client) , 指定数据类型细节的程序叫实现(implementation) 。接口不是透明(opaque)的, 即客户端无法看到(往往也不关心)实现, 更无法直接修改ADT的内部结构。换句话说,可以用接口完全描述一个ADT,即定义ADT所支持的操作。例如刚才的储钱罐就是一个优先队列(priority queue) ADT,每个硬币的优先级就是它的面值。每次优先级最大的出对。

    基本优先队列的操作如下:

    bool empty():判断队列是否为空

    void insert(i, p):往队列里加入一个元素i,优先级为p

    int getmax():取得队列里最大元素并把它从队列里删除

    每次投入一枚面值相当于执行操作insert,按一次按钮相当于先执行empty,如果队列不空,则执行getmax。队列和栈可以看作优先队列的特殊情况。如何把队列和栈看作优先队列的特殊情况?在队列中,把优先级设为入队时间的减函数;在栈中,把优先级设置为入队时间的增函数即可(想一想,为什么)。不过这只是一种可行的方案,并不是最好的。事实上,由于队列和栈的特殊性,通常用数组来实现,插入和删除都是常数级的。

     

    9.电路满足问题给定一个只由AND,OR和NOT组成的n输入-单输出布尔组合电路,是否存在一个输入指派,使得电路输出为1?一个布尔组合电路不能包含有向环。

    Cook定理电路满足问题是NP完全的。

  • 相关阅读:
    Linux查看文件夹大小
    mysql按照天或小时group分组统计
    eclipse可以调试但是无法打开网页,提示一直在加载
    自定义spring valid方式实现验证
    UniCode编码表及部分不可见字符过滤方案
    shiro中移除jsessionid的解决方案
    Apache Shiro去掉URL中的JSESSIONID
    shiro开启realm
    shiro注解@RequiresPermissions多权限任选一参数用法
    linux 复制粘贴
  • 原文地址:https://www.cnblogs.com/hxsyl/p/3092602.html
Copyright © 2011-2022 走看看