您的位置:首页 > 其它

第二届校内程序设计选拔赛部分题解

2014-10-15 16:31 309 查看

前言

       这次比赛共5道题(中文),个人赛。我负责命题3道,这里就写这3题的解题报告。
       总的来说题目难度不大,考虑到毕竟比赛只有2个小时。代号1是字符串水题;代号3是一道经典、简单的动态规划,但我改编后加大了难度;代号2是裸广度优先搜索,但是要搜两轮,考验编程熟练度。我觉得后两道难度中等吧,还算不上难题。
       我考的这些知识点:bfs、读入外挂、滚动数组等,都是比较基本的概念,网上一搜资料一堆,所以我的解题报告会偏精简。然后标程用的都是C++,不懂C++的同学还是抓紧学习吧,玩ACM不会C++很吃亏。

代号1

       判断一个0~1内的高精度小数是否严格大于0.99999999999999999999(20个9)。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

       坑点1:注意double精度只有16位有效数字,故必须用字符串处理。

       坑点2:除了小数点后判断是否出现连续的20个9,还要注意判断接下来是否有非0值。即0.99999999999999999999对应输出的是“No”,估计这一点比赛的时候会让很多人WA,甚至WA了还很难想明白为什么。
#include <iostream>
#include <string>
using namespace std;

string s;

bool func() {
int i;

if (s.size() < 23) return 0;

for (i = 2; i <= 21; i++)
if (s[i] != '9') return 0;

while (i < s.size())
if (s[i++] != '0') return 1;

return 0;
}

int main() {
int T; cin >> T;
while (cin >> s)
cout << (func()?"Yes":"No") << "\n";

return 0;
}


代号2

       一个10*10的网格,一个起点A,六个目的地1~6中任选两个,问最短距离是多少。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

       这题其实算法并不难,主要是考验编程熟练度,能否在有限的比赛时间内完成代码,题型为BFS。

       坑点:注意虽然解一定存在,不代表每个食堂一定能到达,可能一个食堂上下左右会被封锁,估计这点会造成一些人RE。不过更有可能的是因为时间原因,比较少人会选择做这题。后来我把样例改成现在这样,把这个坑点直接告诉大家了。所以降低了难度,能过样例的基本能AC。
       注意标程的一些编程技巧,特别是6个食堂选2个的地方,可以直接用双循环暴力。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int inf = 99999999;

bool can[12][12];		// can[i][j]:原始地图(i,j)点是否可以走

// 在地图中,从(x0,y0)到(x1,y1)的距离
int distance(int x0, int y0, int x1, int y1) {
int dis[12][12] = {}, x, y, d;	// dis用0值代表还未访问

dis[x0][y0] = 1;	// 距离都多加1,最后返回时注意减1

queue<int> pos;
pos.push(100 * x0 + y0);

while(pos.size()) {
x = pos.front()/100;	// 横坐标
y = pos.front()%100;	// 纵坐标
d = dis[x][y];
pos.pop();				// 出队

if (x == x1 && y == y1) return d-1;

#define TEST if(can[x][y] && !dis[x][y]) {dis[x][y]=d+1; pos.push(100*x+y);}

x += 1, y  = y; TEST	// 上
x -= 2, y  = y; TEST	// 下
x += 1, y -= 1; TEST	// 左
y += 2; TEST	// 右
}
return inf;		// 无解
}

int main() {
string s;
int T, x[7], y[7], i, j, ans;		// 存储起点及食堂的坐标

scanf("%d ", &T);
while (T--) {
memset(can, 0, sizeof(can));

for (i = 0; i< 10; i++) {
getline(cin, s);
for (j = 0; j < 10; j++) {	// 地图编号从1开始
if (s[j] != '#') can[i+1][j+1] = 1;
if (s[j] > '0' && s[j] < '7')
x[s[j]-'0'] = i+1, y[s[j]-'0'] = j+1;
else if (s[j] == 'A')
x[0] = i+1, y[0] = j+1;
}
}

ans = inf;
for (i = 1; i <= 6; i++) for (j = 1; j <= 6; j++) {
if (j == i) continue;
ans = min(ans, distance(x[0],y[0],x[i],y[i])+distance(x[i],y[i],x[j],y[j]));
}

cout << ans << "\n";

if (T) getchar();	// 读掉空行
}

return 0;
}


代号3

       一道很经典的动态规划三角形,问从上往下走和最大的走法。但是一般的数据规模是1千行,这里被我放大到3千行。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

       从1千行到3千行,数量是个平方级增长的过程。本来我故意把整数范围设成long long大小,是想让开二维数组解的人直接MLE,不过3000*3000只要44M内存还好~。然后要读入的整数数量非常大,要用读入外挂优化,考虑到降低难度,所以在题目正文直接提到了要用读入外挂做,暗示用scanf会TLE。大白书第40页也有读入外挂的模板,我这里C++版的读入外挂是个函数模板,可以读取任意整型的整数。
       那么不用二维数据怎么解呢?用滚动数组,开个a[2][3001]就够了。可以边导入数据边运算,在每一行,都更新为从第一行到该点的最优解值。最后判断最后一行中的最大值即可。
       不太明白动态规划原理的同学,可以看小白书或紫书动态规划那一章,开篇就是讲数字三角形。
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef unsigned long long LL;

//仅读正整数的读入外挂
template <typename T>
inline void read(T& x) {
char ch; while (!((((ch=getchar())>='0') && (ch <= '9')) || (ch == '-')));
x = ch-'0'; while (((ch=getchar())>='0') && (ch <= '9')) x = x*10+ch-'0';
}

int main() {
int n, i, j, now, T;

read(T);
while (T--) {
read(n);

LL a[2][3001] = {};
for (now = i = 1; i <= n; i++) {
now ^= 1;
for (j = 1; j <= i; j++) {
read(a[now][j]);
a[now][j] += max(a[now^1][j-1], a[now^1][j]);
}
}
cout << *max_element(&a[now][1], &a[now][n+1]) << "\n";
}
return 0;
}


后记

       看来还是出难了,结果有点惨烈~~~C题本来卡32M内存的,但是校OJ给的是64M,所以也可以用开辟二维数组做,但要注意代码效率。
       文中小白书指的是刘汝佳的《算法竞赛入门经典》,大白书是《算法竞赛入门经典——训练指南》,紫书是指小白书的第二版,是非常好的ACM学习教材,推荐大家使用。
       解题报告有疑问的可以跟我交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: