《挑战程序设计竞赛》2.1 穷竭搜索 POJ2718 POJ3187 POJ3050 AOJ0525
POJ2718
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6509 | Accepted: 1773 |
Description
For example, if you are given the digits 0, 1, 2, 4, 6 and 7, you can write the pair of integers 10 and 2467. Of course, there are many ways to form such pairs of integers: 210 and 764, 204 and 176, etc. The absolute value of the difference between the integers in the last pair is 28, and it turns out that no other pair formed by the rules above can achieve a smaller difference.
Input
Output
Sample Input
1 0 1 2 4 6 7
Sample Output
28
Source
题意:
0-9中不重复的几个数,若分成两堆分别组合成一个十进制数(首位不能是0),问两个数的差最小是多少?
思路:
假设总共有n个数,很显然一堆所使用的数字个数应该为n/2,另一堆用剩下的。先选择n/2个数,利用全排列性质遍历所有排列顺序,也就遍历了第一个数,对第二个数也类似遍历,求其差的最小值即可。
C++中提供的
next_permutation
函数在帮助遍历全排列时可提供很大帮助。
代码:
Source Code Problem: 2718 User: liangrx06 Memory: 204K Time: 469MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int INF = 1000000; int a[10]; int n; void input() { n = 0; char ch; while ( (ch = getchar()) != '\n' ) { if (ch == ' ') continue; a[n++] = ch - '0'; } } void solve() { int res = INF; int half = n/2; int i, x, y; do { if (half >= 2 && a[0] == 0) continue; if (n - half >= 2 && a[half] == 0) continue; x = 0; for (i = 0; i < half; i ++) x = x * 10 + a[i]; y = 0; for (i = half; i < n; i ++) y = y * 10 + a[i]; int tmp = (x > y) ? (x - y) : (y - x); if (tmp < res) res = tmp; } while (next_permutation(a, a + n)); printf("%d\n", res); } int main(void) { int t; cin >> t; getchar(); while (t--) { input(); solve(); } return 0; }
POJ3187
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5409 | Accepted: 3121 |
Description
3 1 2 4 4 3 6 7 9 16Behind FJ's back, the cows have started playing a more difficult game, in which they try to determine the starting sequence from only the final total and the number N. Unfortunately, the game is a bit above FJ's mental arithmetic capabilities.
Write a program to help FJ play the game and keep up with the cows.
Input
Output
Sample Input
4 16
Sample Output
3 1 2 4
Hint
There are other possible sequences, such as 3 2 1 4, but 3 1 2 4 is the lexicographically smallest.
Source
题意:
给定1-n的某个排列,对其相邻的两个数相加得到n-1个数的数列,重复相加过程最终将得到一个数。
现在已知n以及操作后最终的结果sum,求原始排列(输出字典序最小的那个)。
思路:
简单分析后可以知道,原始排列中每个数的累加次数对应于n的二项式分解系数C(n,i)。对1-n的排列进行字典序遍历,第一个符合结果的排列就是答案。
代码:
Source Code Problem: 3187 User: liangrx06 Memory: 204K Time: 16MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int INF = 1000000; int a[10]; int n; int c[10]; int fact(int x) { int res = 1; while (x) res *= x--; return res; } void init() { int i; for (i = 0; i < 10; i ++) { a[i] = i+1; if (i < n) c[i] = fact(n-1)/fact(i)/fact(n-1-i); } } void solve(int sum) { int i; do { int tmp = 0; for (i = 0; i < n; i ++) tmp += a[i] * c[i]; if (tmp == sum) break; } while (next_permutation(a, a + n)); for (i = 0; i < n-1; i ++) printf("%d ", a[i]); printf("%d\n", a[i]); } int main(void) { int sum; while (cin >> n >> sum) { init(); solve(sum); } return 0; }
POJ3050
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2775 | Accepted: 1941 |
Description
They then adroitly hop onto any digit in the grid and hop forward, backward, right, or left (never diagonally) to another digit in the grid. They hop again (same rules) to a digit (potentially a digit already visited).
With a total of five intra-grid hops, their hops create a six-digit integer (which might have leading zeroes like 000201).
Determine the count of the number of distinct integers that can be created in this manner.
Input
Output
Sample Input
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1
Sample Output
15
Hint
111111, 111112, 111121, 111211, 111212, 112111, 112121, 121111, 121112, 121211, 121212, 211111, 211121, 212111, and 212121 can be constructed. No other values are possible.
Source
题意:
给定一片5*5的土地,一只牛在上面初始任意位置,它每次可以上下左右直线跳到任意位置。求牛跳5次所形成的的路径(比如111121)的个数。
思路:
递归穷竭搜索。
我的程序中考虑了路径重复问题,因此存储路径使用了set(其中无重复元素)。但特殊数据结构的维护似乎抵消了存储复杂度降低所带来的好处,因而时间复杂度仍不算低。
代码:
Source Code Problem: 3050 User: liangrx06 Memory: 1064K Time: 219MS Language: C++ Result: Accepted Source Code #include <iostream> #include <cstdio> #include <set> using namespace std; int a[5][5]; set<int> s[2][5][5]; void input() { int i, j; for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { cin >> a[i][j]; } } } void solve() { int i, j, k, x, y; set<int>::iterator it; int pos[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; for (k = 0; k < 6; k ++) { for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { if (k == 0) { s[k&1][i][j].insert(a[i][j]); continue; } s[k&1][i][j].clear(); for (int m = 0; m < 4; m ++) { x = i + pos[m][0]; y = j + pos[m][1]; if (x >= 0 && x < 5 && y >= 0 && y < 5) { for (it = s[(k-1)&1][x][y].begin(); it != s[(k-1)&1][x][y].end( ); it ++) s[k&1][i][j].insert((*it)*10 + a[i][j]); } } } } } set<int> sall; for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { for (it = s[1][i][j].begin(); it != s[1][i][j].end(); it ++) sall.insert((*it)); } } printf("%d\n", sall.size()); } int main(void) { input(); solve(); return 0; }
AOJ0525
原题链接:
题意:
题目大意是说,有一个煎饼器,可以烤R行C列的煎饼,煎饼可以正面朝上(用1表示),也可以背面朝上(用0表示),一次可以翻转一整行或一整列的煎饼。现在需要把尽量多的煎饼翻成正面朝上,给定煎饼的当前状态,问经过翻转后,最多能使多少煎饼正面朝上。
思路:
因为列数很大,行数只有10,所以枚举出10行所有的情况只有
枚举的话,先从行开始,一共有
我看其他很多人用了bitset,关注了一下运行时间发现并无优势,自己用位操作照样实现的很好。
代码:
#include <iostream> #include <cstdio> using namespace std; const int C = 10000; int r, c; int a[C]; void input() { cin >> r >> c; fill(a, a+c, 0); int x, n = 1; for (int i = 0; i < r; i ++) { for (int j = 0; j < c; j ++) { scanf("%d", &x); a[j] |= (x ? n : 0); } n <<= 1; } } void solve() { int res = 0; for (int k = 0; k < (1<<r); k ++) { int count = 0; for (int j = 0; j < c; j ++) { int count0 = 0, n = 1; for (int i = 0; i < r; i ++) { if ((a[j]^k)&n) count0 ++; n <<= 1; } count += ( (count0 > r/2) ? count0 : (r-count0) ); } res = (res > count) ? res : count; } printf("%d\n", res); } int main(void) { while (cin >> r >> c) { if (!r && !c) break; fill(a, a+c, 0); int x, n = 1; for (int i = 0; i < r; i ++) { for (int j = 0; j < c; j ++) { scanf("%d", &x); a[j] |= (x ? n : 0); } n <<= 1; } solve(); } return 0; }