• 重拾ZOJ 一周解题


    ZOJ 2734 Exchange Cards

    题目大意:

    给定一个值N,以及一堆卡片,每种卡片有一个值value和数量number。求使用任意张卡片组成N的方式。

    例如N = 10 ,cards(10,2)(7,2)(5,3)(2,2)(1,5),则10 = 10,10 =7+3+1,10=5+5…

    思路分析:

    由于之前做过1204,知道这题就是赤裸裸的搜索,直接用dfs暴力即可求得。

    可做的优化处理就是——这个过程是贪心Greedy的,先从大到小这样取过来,所以,可以做一步降序排列的预处理。

    如上例:我选择了7,那么我就不会去选择10,因为加上10太大了,超出了N。

    知识点总结:

    1) DFS走法:沿着可行的解空间往前走;

    dfs(index, number, sum, target);

    2) 循环走法:选择下一个起点枚举;

    dfs(++index, 1, sum, target);

    代码:

    #include<iostream>
    #include<vector>
    #include<map>
    #include<algorithm>
    #include<fstream>
    using namespace std;
    
    struct Cards
    {
        int num;
        int value;
        bool operator <(const Cards& card)const
        {
            return value > card.value;
        }
    };
    
    int totalCardsCount;
    vector<Cards> inputValues;
    
    void dfs(int index, int number, int sum, int target)
    {
        if (sum == target) //记录总述
        {
            totalCardsCount++;
            return;
        }
        if (index == inputValues.size()) return; //长度
    
        //能加则加,deep ing ... ...
        if (sum + inputValues[index].value <= target && number <= inputValues[index].num)
        {
            sum += inputValues[index].value;
            number++;
            dfs(index, number, sum, target);
            number--;
            sum -= inputValues[index].value;
        }
    
        dfs(++index, 1, sum, target);
    }
    
    int main()
    {
        //ifstream cin("2734.txt");
        int T, i, target;
        int c = 0;
        int n;
        bool first = true;
        while (cin >> target){
            if (!first)
            {
                cout << endl;
            }
            first = false;
            c = 1;
            cin >> n;
            inputValues.clear();
            int tmp;
            for (i = 1; i <= n; i++)
            {
                Cards cd;
                cin >> cd.value;
                cin >> cd.num;
                inputValues.push_back(cd);
            }
            std::sort(inputValues.begin(), inputValues.end());
            totalCardsCount = 0;
            dfs(0, 1, 0, target);
            cout << totalCardsCount << endl;
        }
        return 0;
    }

    ZOJ 1947 The Settlers of Catan

    题目大意:

    给出一个无向图,求这个无权无向图的最长路径——the longest path。即,在图中找一条边不重复(点可以重复)的路径,所得的路径的边的条数即为所求。

    如:3个点,两条边,(0,1)(1,2),则the longest path 为2。

    图的最大规模为25*25。

    思路分析:

    看到这题,试图去网上搜索最长路径的知识点,但是始终找不到有用的。最后,我将起点放在欧拉回路的概念上,然后又了解到哈密顿回路,得出一个结论,求最长路径比欧拉回路更为广泛。

    不小心浏览到维基百科,知道这是一个NP问题,其算法只能是暴力枚举。更了解到如果是有向图的最长路径的话应该先做拓扑排序预处理。

    于是,直接对每个点进行dfs搜索,每次保存最长路径即可。

    知识点总结:

    1) 欧拉回路:经过图中所有边一次仅一次且行遍所有顶点的回路。

    2) 哈密顿回路:经过图中所有顶点一次仅一次的回路。

    代码:

    #include <stdio.h>
    #include<iostream>
    #include<vector>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<cstring>
    #include<fstream>
    #include<list>
    using namespace std;
    
    int graph[26][26];
    bool visited[26][26];
    
    int theLongestPath;
    void dfs(int root, int d)
    {
        if (d > theLongestPath)
        {
            theLongestPath = d;
        }
    
        for (int i = 0; i < 26; i++)
        {
            if (root == i) continue;
            if (graph[root][i] == 1 && visited[root][i] == 0)
            {
                visited[root][i] = visited[i][root] = 1;
                ++d;
                dfs(i, d);
                --d;
                visited[root][i] = visited[i][root] = 0;
            }
        }
    }
    
    int main1947()
    {
        //fstream cin("1947.txt");
        int n, m;
        while (cin >> n >> m)
        {
            if (n == 0 && m == 0)break;
            memset(graph, 0, sizeof(graph));
    
            int start, end;
            for (int i = 0; i < m; i++) 
            {
                cin >> start >> end;
                graph[start][end] = graph[end][start] = 1;
            }
    
            theLongestPath = 0;
            for (int i = 0; i < n; i++)
            {
                memset(visited, 0, sizeof(visited));
                dfs(i, 0);
            }
            cout << theLongestPath << endl;
    
        }
        return 0;
    }

    ZOJ 1978 Assistant Required

    题目大意:

    给定一个队列,2,3,。。。n,每次取队首元素作为幸运元素,然后将其后的每隔i个给拖出去干活。比如,第一次2是幸运的,4,6,8…就要干活;第二次3是幸运的,9,15,21。。。就要去干活。。。

    求第K个幸运数字。

    思路分析:

    从2写道20的序列分析,发现和素数很像,甚至就做成了素数表。

    但当测试第20个幸运数时,Sample Out给出的是83,我打出来的是71(还是73,具体忘了),发现错了,于是再分析之下,发现和素数表有点区别。

    素数表:每次去除i的倍数;

    幸运数字(暂且这么称吧)表:每次去除每隔i的数。

    修改之,即可。

    知识点总结:

    1) 素数表;

    代码:

    #include<iostream>
    #include<vector>
    #include<map>
    #include<string>
    #include<algorithm>
    #include<fstream>
    using namespace std;
    
    const int MAX_Prime = 3001;
    const int SEARCH_INT = 34000;
    
    int prime_like[MAX_Prime];
    bool is[SEARCH_INT];
    
    void make_prim_table()
    {
        for (int i = 0; i < MAX_Prime; i++)
        {
            is[i] = 0;
        }
        int num = 1;
        for (int i = 2; i < SEARCH_INT; i++)
        {
            if (is[i] == 1) continue;
            if (is[i] == 0)
            {
                prime_like[num++] = i;
                if (num == MAX_Prime) break;
            }
            if (i == 2)
            {
                for (int k = i; k < SEARCH_INT; k += i)
                {
                    is[k] = 1;
                }
            }
            else
            {
                int number = 0;
                for (int k = i + 1; k < SEARCH_INT; k++)
                {
                    if (is[k] == 0)  //已经出队
                    {
                        if (++number == i)
                        {
                            is[k] = 1;
                            number = 0;
                        }
                    }
                }
            }
        }
    }
    
    int main1978()
    {
        make_prim_table();
        //fstream cin("1978.txt");
        int n;
        while (true)
        {
            cin >> n;
            if (n == 0)break;
            cout << prime_like[n] << endl;
        }
        return 0;
    }

    Acceptted is the best thing for you ~

  • 相关阅读:
    【剑指Offer面试编程题】题目1370:数组中出现次数超过一半的数字--九度OJ
    【剑指Offer面试编程题】题目1369:字符串的排列--九度OJ
    【剑指Offer面试编程题】题目1503:二叉搜索树与双向链表--九度OJ
    【剑指Offer面试编程题】题目1524:复杂链表的复制--九度OJ
    【剑指Offer面试编程题】题目1368:二叉树中和为某一值的路径--九度OJ
    【剑指Offer面试编程题】题目1367:二叉搜索树的后序遍历序列--九度OJ
    【剑指Offer面试编程题】题目1523:从上往下打印二叉树--九度OJ
    【剑指Offer面试编程题】题目1366:栈的压入、弹出序列--九度OJ
    【剑指Offer面试编程题】题目1522:包含min函数的栈--九度OJ
    【剑指Offer面试编程题】题目1391:顺时针打印矩阵--九度OJ
  • 原文地址:https://www.cnblogs.com/pengzhen/p/4393198.html
Copyright © 2020-2023  润新知