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 ~