今年上半学期的校队选拔题目,是从poj上抽的几道题。为了照顾尚未学习算法和数据结构的同学,同时结合前几次培训的内容,考察了模拟,搜索和数学题目,总体来说,题目没有太大的难度,但两道搜索较为繁杂,需要考虑一些细节问题,同时也要求良好的编写代码能力。编写代码能力是ACM学习的基础,希望各位同学能多花时间写一写题,加强编写代码的能力。若对题解有疑问,可在下方评论或直接与我联系。
【POJ2739】Sum of Consecutive Prime Numbers
对给定的一个数k,寻找可以被连续素数之和组成的方案数,由于在[1,10000]区间内的素数只有小于1300个,可以直接用素数筛找出所有素数后,通过枚举所有方案,得到答案。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int maxn = 10000;
int prime[maxn + 10],m = 0;
int cou[maxn + 10];
bool vis[maxn + 10];
int init() {
for (int i = 2;i <= maxn; i++)
if (!vis[i]) {
prime[++m] = i + prime[m-1];
for (int j = i+i;j <= maxn; j += i) vis[j] = true;
}
for (int i = 1;i <= m; i++)
for (int j = i-1;j >= 0; j--)
if (prime[i]-prime[j] <= maxn) cou[prime[i]-prime[j]]++;
else break;
}
int main() {
init();
int n;
while (scanf("%d",&n) != EOF) {
if (!n) break;
printf("%d\n",cou[n]);
}
return 0;
}
【POJ1573】Robot Motion
模拟题,求机器人在题中给出地图中行走的步数,根据题目中给定的规则执行即可,注意字符的读取。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int mov[4][2] = {-1,0,1,0,0,1,0,-1};
int n,m,k;
char a[1010][1010];
int vis[1010][1010];
map<char,int> dir;
bool is_sta(int x,int y) {
if (x < 1 || x > n || y < 1 || y > m) return false;
return true;
}
int main() {
dir['N'] = 0;dir['S'] = 1;dir['E'] = 2;dir['W'] = 3;
while (scanf("%d%d%d%*c",&n,&m,&k) != EOF) {
memset(vis,0,sizeof(vis));
if (n == 0 && m == 0 && k == 0) break;
for (int i = 1;i <= n; i++) {
for (int j = 1;j <= m; j++) scanf("%c",&a[i][j]);
scanf("%*c");
}
int x = 1,y = k,cou = 1;
int s1 = 0,s2 = 0;
vis[x][y] = 1;
while (true) {
int d = dir[a[x][y]];
x += mov[d][0];
y += mov[d][1];
//cout << x <<":" << y << endl;
if (!is_sta(x,y)) {
s1 = cou;
break;
}
if (vis[x][y]) {
s1 = vis[x][y] - 1;
s2 = cou - vis[x][y] + 1;
break;
}
vis[x][y] = ++cou;
}
if (s2) printf("%d step(s) before a loop of %d step(s)\n",s1,s2);
else printf("%d step(s) to exit\n",s1);
}
return 0;
}
【POJ2109】Power of Cryptography
给出n,p,求使k^n = p的k,之前我做这道是用对数做的,后来发现直接开方就可以OTZ,所以其实这才是最水的一道题。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
int main() {
double n,p;
while (scanf("%lf%lf",&n,&p) != EOF) {
double k = log2(p)/n;
int ans = pow(2,k) + eps;
//像这样也可以过OTZ
// int ans = (double)pow(p,1/n) + eps;
printf("%d\n",ans);
}
return 0;
}
【POJ3009】Power of Cryptography
DFS深度优先搜索,因为数据范围很小,不用加优化也可以通过,枚举每次滚动的方向进行搜索。值得注意的一点:本题中是先给列数,再给的行数。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
const int mov[4][2] = {1,0,-1,0,0,1,0,-1};
int n,m,ans;
int a[30][30];
bool is_sta(int x,int y) {
if (x < 1 || x > n || y < 1 || y > m) return false;
return true;
}
void dfs(int x,int y,int step) {
if (step > 10) return;
for (int i = 0;i < 4; i++) {
if (a[x+mov[i][0]][y+mov[i][1]] == 1) continue;
int nx = x,ny = y;
while (is_sta(nx,ny) && a[nx][ny] != 3 && a[nx][ny] != 1) {
nx += mov[i][0];
ny += mov[i][1];
}
if (!is_sta(nx,ny)) continue;
if (a[nx][ny] == 3) {
if (ans == -1) ans = step;
else ans = min(ans,step);
}
if (a[nx][ny] == 1) {
a[nx][ny] = 0;
dfs(nx-mov[i][0],ny-mov[i][1],step+1);
a[nx][ny] = 1;
}
}
}
int main() {
while (scanf("%d%d",&m,&n) != EOF) {
memset(a,0,sizeof(a));
if (n == 0 && m == 0) break;
int x,y;
for (int i = 1;i <= n; i++)
for (int j = 1;j <= m; j++) {
scanf("%d",&a[i][j]);
if (a[i][j] == 2) {x = i;y = j;}
}
ans = -1;
dfs(x,y,1);
printf("%d\n",ans);
}
return 0;
}
【POJ3414】Pots
BFS宽度优先搜索,可视为无权图最短路问题,用BFS解决,在每轮中枚举六种操作,第一次找到的解即为最优解,之后递归输出方案。
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
struct point {
int x,y,f,act;
};
point line[10100];
bool vis[110][110];
void print(int k,int cnt) {
if (line[k].f) print(line[k].f,cnt+1);
else printf("%d\n",cnt);
if (line[k].act == 1) puts("FILL(1)");
if (line[k].act == 2) puts("FILL(2)");
if (line[k].act == 3) puts("DROP(1)");
if (line[k].act == 4) puts("DROP(2)");
if (line[k].act == 5) puts("POUR(1,2)");
if (line[k].act == 6) puts("POUR(2,1)");
}
int main() {
int a,b,c;
while (scanf("%d%d%d",&a,&b,&c) != EOF) {
memset(vis,0,sizeof(vis));
int p1 = 1,p2 = 1;
line[p2++] = (point){0,0,0};
vis[0][0] = true;
bool ans = false;
while (p1 < p2) {
point p = line[p1];
if (p.x == c || p.y == c) {
print(p1,0);
ans = true;
break;
}
if (!vis[a][p.y]) {
line[p2++] = (point){a,p.y,p1,1};
vis[a][p.y] = true;
}
if (!vis[p.x][b]) {
line[p2++] = (point){p.x,b,p1,2};
vis[p.x][b] = true;
}
if (!vis[0][p.y]) {
line[p2++] = (point){0,p.y,p1,3};
vis[0][p.y] = true;
}
if (!vis[p.x][0]) {
line[p2++] = (point){p.x,0,p1,4};
vis[p.x][0] = true;
}
int x = p.x,y = p.y;
if (p.x + p.y > b) x = p.x+p.y-b,y = b;
else x = 0,y = p.x+p.y;
if (!vis[x][y]) {
line[p2++] = (point){x,y,p1,5};
vis[x][y] = true;
}
x = p.x,y = p.y;
if (p.x + p.y > a) x = a,y = p.x+p.y-a;
else x = p.x+p.y,y = 0;
if (!vis[x][y]) {
line[p2++] = (point){x,y,p1,6};
vis[x][y] = true;
}
p1++;
}
if (!ans) puts("impossible");
}
return 0;
}
【POJ1850】Code
递推,计算给出的字符串是第几个递增字符串,f[i][j]表示最高位是第i位,第i位为j(0 <= j < 26)的递增字符串个数,递推式为
f[i][j] = sum(f[i-1][k](1 <= k < 26))(j = 0)
f[i][j] = f[i][j-1] - f[i][j] (0 < j < 26)
#include<iostream>
#include<cstdio>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<cmath>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
string st;
int f[20][30];
void init() {
for (int i = 0;i < 26; i++) f[1][i] = 1;
for (int i = 2;i <= 10; i++) {
for (int j = 1;j < 26; j++) f[i][0] += f[i-1][j];
for (int j = 1;j <= 26-i; j++) f[i][j] = f[i][j-1] - f[i-1][j];
}
}
int main() {
init();
while (cin >> st) {
int ans = 0,n = st.length();
for (int i = 1;i < n; i++) {
if (st[i] < st[i-1]) {
ans = -1;
break;
}
}
if (ans == -1) {
printf("%d\n",0);
break;
}
for (int i = n;i > 0; i--) {
for (int j = 0;j <= st[n-i]-'a'; j++) ans += f[i][j];
}
printf("%d\n",ans);
}
return 0;
}
到此,本学期与ACM有关的活动已经全部结束,回顾月赛,新秀杯和这次的选拔赛,不知道大家在ACM中收获了什么?如果能在coding感受到快乐的话,那是再好不过了。时间已经临近期末,也请大家好好复习,祝大家在期末考试中能取得好成绩!另外,校集训队会在寒假中组织培训,主要内容为动态规划(DP)及图论算法。
我们寒假再见!
PS:天气太冷我已经冻感冒了,大家也注意身体(吸鼻涕,总之早点睡觉多喝热水总是没错的。