重拾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 ~

你可能感兴趣的:(ZOJ)