【牛客网】2018年北京信息科技大学第十届程序设计竞赛暨ACM选拔赛 全题解

因为是新生选拔赛所以题目总体不难,但是不乏坑题(数学题和物理题)

题目都是中文题,只要题目没有歧义我基本只会讲解法。

A PUBG

bfs,设一个数组vis[i][j]表示从起点到(i,j)的最小数值,然后bfs就行了。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
struct nodes {
	int x, y;
	nodes(int _x = 0, int _y = 0) :x(_x), y(_y) {}
};
int vis[111][111];
int mp[111][111], n;
int dx[] = { 0,0,1,-1 }, dy[] = { 1,-1,0,0 };
nodes st, en;
bool check(int x, int y) {
	if (x < 0 || y < 0 || x >= n || y >= n) return true;
	return false;
}
void bfs() {
	memset(vis, 0x3f, sizeof(vis));
	queue<nodes>que;
	que.push(st);
	vis[st.x][st.y] = 0;
	while (!que.empty()) {
		nodes tmp = que.front();
		que.pop();
		for (int i = 0; i < 4; i++) {
			int tx = tmp.x + dx[i], ty = tmp.y + dy[i];
			if (check(tx, ty))continue;
			if (tx == en.x&&ty == en.y){
				vis[tx][ty] = min(vis[tx][ty], vis[tmp.x][tmp.y]);
				continue;
			}
			if (vis[tmp.x][tmp.y] + mp[tx][ty] < vis[tx][ty]) {
				que.push(nodes(tx, ty));
				vis[tx][ty] = vis[tmp.x][tmp.y] + mp[tx][ty];
			}
		}
	}
}
int main() {
	while (~scanf("%d", &n)) {
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				scanf("%d", &mp[i][j]);
				if (mp[i][j] == -1) st = nodes(i, j);
				else if (mp[i][j] == -2) en = nodes(i, j);
			}
		}
		bfs();
		printf("%d\n", vis[en.x][en.y]);
	}
	return 0;
}

B precise math function

需要精度高的pi,读者可以直接复制高高精度的pi,或者用acos(-1)表示(笔者推荐后者)

因为要由变量确定精度,所以用c++的iomanip头文件中的输出修正

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int a, b;
		scanf("%d%d", &a, &b);
		double ans = pow(a, PI);
		cout << fixed << setprecision(b) << ans << endl;;
	}
	return 0;
}

C 颜料的混合

这里的颜料混合和盐水稀释是一个道理的,所以除了要考虑浓度之外还要注意混合是体积也会有影响。

根据盐水稀释,如果把浓度和体积设为横坐标和纵坐标,两倍盐水能稀释的范围在两点连线上的点。

以此类推,三个点的话能稀释的范围就是在三角形内。

扫描二维码关注公众号,回复: 2509603 查看本文章

问题转换为点是否在三角形内。

读者可以直接用几何模板,这里笔者提供一种三角形的思路。

如果点在三角形内,那么点把三角形分割成三个三角形,这三个三角形的面积和和原来的一定相等。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int area(int x1, int y1, int x2, int y2) { return abs(x1 * y2 - x2 * y1); }

int main() {
	int x0, y0, x1, y1, x2, y2, x3, y3;
	while (cin >> x0 >> y0 >> x1 >> y1 >> x2 >> y2 >> x3 >> y3) {
		int tri = area(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
		int s1 = area(x1 - x0, y1 - y0, x2 - x0, y2 - y0);
		int s2 = area(x2 - x0, y2 - y0, x3 - x0, y3 - y0);
		int s3 = area(x1 - x0, y1 - y0, x3 - x0, y3 - y0);
		if (s1 + s2 + s3 == tri)
			cout << "Yes" << endl;
		else
			cout << "No" << endl;
	}
	return 0;
}

D 打篮球

直接模拟就行了

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int num[111];
int main() {
	int n;
	while (~scanf("%d", &n)) {
		int a[4];
		a[1] = 1, a[2] = 2, a[3] = 3;
		for (int i = 0; i < n; i++)
			scanf("%d", &num[i]);
		bool flag = true;
		for (int i = 0; i < n; i++) {
			if (a[1] == num[i] || a[2] == num[i]) {
				if (a[1] == num[i]) swap(a[2], a[3]);
				else swap(a[1], a[3]);
			}
			else {
				flag = false;
				break;
			}
		}
		printf("%s\n", flag ? "YES" : "NO");
	}
	return 0;
}

E 233

大数乘法随便来

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
t=int(input())
for x in range(t):
    a,b=input().split( )
    a=int(a)
    b=int(b)
    a=a*b
    print(a)

F 扫雷

因为如果没有扫到雷要求输出矩阵,所以要设一个数组保留最后答案。

扫到的点分三种

1:扫到雷,直接返回失败。

2:扫到数字,把这个数字赋值给答案数组。

3:扫到.,把剩余的八联通块进行bfs。

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
struct nodes {
	int x, y;
	nodes(int a = 0, int b = 0) :x(a), y(b) {}
}ser[15];
int n, m;
char ansmp[555][555], mp[555][555];
int dx[] = { 0,0,1,-1,-1,-1,1,1 }, dy[] = { 1,-1,0,0,-1,1,-1,1 };
bool vis[555][555];
bool check(int x, int y) {
	if (x < 0 || x >= n || y < 0 || y >= m) return true;
	else if (vis[x][y]) return true;
	return false;
}
bool bfs(int x, int y) {
	if (mp[x][y] == '*') return true;
	else if (mp[x][y] >= '1'&&mp[x][y] <= '8') {
		vis[x][y] = true;
		ansmp[x][y] = mp[x][y];
		return false;
	}
	else {
		queue<nodes>que;
		que.push(nodes(x, y));
		ansmp[x][y] = '0';
		while (!que.empty()) {
			nodes tmp = que.front();
			que.pop();
			int nx = tmp.x, ny = tmp.y;
			for (int i = 0; i < 8; i++) {
				int tx = nx + dx[i], ty = ny + dy[i];
				if (check(tx, ty)) continue;
				vis[tx][ty] = true;
				if (mp[tx][ty] >= '1'&&mp[tx][ty] <= '8') 
					ansmp[tx][ty] = mp[tx][ty];
				else {
					ansmp[tx][ty] = '0';
					que.push(nodes(tx, ty));
				}
			}
		}
		return false;
	}
}
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int q;
		scanf("%d%d%d", &n, &m, &q);
		for (int i = 0; i < n; i++) {
			scanf("%s", mp[i]);
			for (int j = 0; j < m; j++) {
				ansmp[i][j] = '.';
				vis[i][j] = 0;
			}
		}
		bool flag = true;
		int ans = 0;
		for (int i = 0; i < q; i++) 
			scanf("%d%d", &ser[i].x, &ser[i].y);
		for (int i = 0; i < q; i++) {
			if (bfs(ser[i].x - 1, ser[i].y - 1)) {
				flag = false;
				ans = i + 1;
				break;
			}
		}
		if (!flag) printf("Game over in step %d\n", ans);
		else {
			for (int i = 0; i < n; i++)
				printf("%s\n", ansmp[i]);
		}
	}
	return 0;
}

G 火车上的2连座

签到题

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
char str[1111][10];
int main() {
	int n;
	while (~scanf("%d", &n)) {
		bool flag = false;
		for (int i = 0; i < n; i++) {
			scanf("%s", str[i]);
			if (flag)continue;
			if (str[i][0] == 'O'&&str[i][1] == 'O') {
				flag = true;
				str[i][0] = str[i][1] = '+';
			}
			else if (str[i][3] == 'O'&&str[i][4] == 'O') {
				flag = true;
				str[i][3] = str[i][4] = '+';
			}
		}
		if (!flag) printf("NO\n");
		else {
			printf("YES\n");
			for (int i = 0; i < n; i++)
				printf("%s\n", str[i]);
		}
	}
	return 0;
}

H 程序员的好印象

实际为一个非严格递增的lis

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int dp[111], num[111];
int lis(int l) {
	dp[1] = num[1];
	int len = 1;
	for (int i = 2; i <= l; ++i) {
		if (num[i] >= dp[len])
			dp[++len] = num[i];
		else {
			int pos = upper_bound(dp + 1, dp + len + 1, num[i]) - dp;
			dp[pos] = num[i];
		}
	}
	return len;
}
int main() {
	int n;
	while (~scanf("%d", &n)) {
		memset(dp, 0, sizeof(dp));
		for (int i = 1; i <= n; i++)
			scanf("%d", &num[i]);
		printf("%d\n", lis(n));
	}
	return 0;
}

I 郊游

数学题。非常要命

首先要说一些题目问题。

车和人是同时从起点出发的。题目要求输出的是最短时间,也就是最优解。车是可以随时放人下车和掉头的。

那么先说结论,为了让车被使用的效率最高,除了最后一批人是坐车直接到目的地之外。

每一批人都是 走路一段-》上车-》车走一段-》下车走-》终点的流程。并且人都是同时到达的(包括最后一批坐车的)

车就是在不断来回接人。

之所以不直接载到终点是为了尽量多用车代步使用时减少。

那么问题来了车在哪里放人下车最优。

首先先说几个结论,1:每一批人走的距离是一样的。2:车载每一批人行驶的距离也是一样的(理由是因为要同时到达)

设一共有p批人

对于第一批人,起点为0的位置,如果他们是在x位置下车的,那么车回头和向前走的人相遇地点在2*v1*x/(v1+v2) (这里读者自己证明),设其为y。

对于第二批人起点在y,根据上面的公式可知车会在2*y的位置和向前走的人相遇。

......

第p批的时候起点在(p-1)*y,因为他们是直接坐车到终点的,坐车距离是x

那么有关系式 L-(p-1)*y=x

化简得x=l*(v1 + v2) / (2.0*v1*(p - 1) + v1 + v2)

结果就为x/v2+(l-x)/v1

(数学题惹不起)

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int main() {
	int n, k, m;
	double l, v1, v2;
	scanf("%d", &m);
	while (m--) {
		scanf("%d%lf%lf%lf%d", &n, &l, &v1, &v2, &k);
		int p = n / k + (n%k == 0 ? 0 : 1);
		double x = l*(v1 + v2) / (2.0*v1*(p - 1) + v1 + v2);
		printf("%.10lf\n", x / v2 + (l - x) / v1);
	}
	return 0;
}

J 过河

物理题。

首先要确定一点的是题目要求的是船头一直指向正对岸,这是船是走曲线的。

建立坐标系,设船到起点的坐标为r,水平位移为x

那么有

对两者求积分可得


解得

然后因为这是一道原题,读者觉得不清楚可以百度。

题号hdu 5761

#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#include<cstdio>
#include<functional>
#include<iomanip>
#include<cmath>
#include<stack>
#include<iomanip>
#include<functional>
#include <iomanip> 
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int maxn = (int)1e5 + 10;
const int BN = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-6;
const double r = 6371009;
const double PI = acos(-1);
int a, v1, v2;
int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d%d", &a, &v1, &v2);
		if (a == 0)
			printf("0.0000000000\n");
		else if (v1 <= v2)
			printf("Infinity\n");
		else
			printf("%.10f\n", 1.0*a*v1 / (v1*v1 - v2*v2));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiuya19/article/details/80280156
今日推荐