面向信息学竞赛、GESP、蓝桥杯等比赛的教学研究、问题讨论、刷题交流,适合各阶段中小学生,平台入口:csp.magu.ltd。
目录
T1、基站
【问题描述】
一个n×m的矩形,单元格(x,y) 表示其位于第x 行第 y列。科学家发明了一种新型网络系统,这种新型网络系统中可以建立多个子网,每个子网需要建立一个1号基站(x1,y1) 和2号基站,该子网可以覆盖以(x1,y1)和(x2,y2) 为顶点的矩形区域(矩形区域的四条边必须平行于行和列)。
1号基站只能在标记为 1的单元格中建立, 2号基站只能在矩形的四个顶点单元格(标记为2 ) 中建立。
不同的子网覆盖区域之间可以相互重叠。
同一个单元格可以建立多个基站。
问最少需要建立多少个子网能将矩形中所有的单元格覆盖。
【输入】
第 1行 1个整数 T,表示有 T组测试数据,每一组数据输入如下:
第 1行 2个整数 n,m,表示矩形的行数和列数。
接下来 n行描述了矩形中单元格的属性。
第 i行包含 m个整数ai,1,ai,2,……,ai,m,用空格分隔。如果 ai,j为 0,表示单元格 (i,j)不能建立任何基站。如果ai,j为1 ,表示单元格 (i,j)可以建立 1号基站。如果 ai,j为 2,表示单元格(i,j) 可以建立 2号基站。
【输出】
输出 T行,每行 1个整数,表示如果能将所有单元格覆盖,需要建立的最少子网数量。
【输入输出样例1】
net.in | net.out |
1 4 4 2 0 0 2 0 1 0 0 0 0 1 0 2 0 0 2 | 4 |
【代码】
#include <iostream>
using namespace std;
int a[110][110];
void solve()
{
int n, m;
cin >> n >> m;
bool f = 0;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
cin >> a[i][j];
if ((i==1||j==1||i==n||j==m) && a[i][j] == 1) {
f = 1;
}
}
}
int ans = f ? 2 : 4;
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
while (T --)
{
solve();
}
return 0;
}
T2、货车配送
【问题描述】
某个街区是一个 n × m 的网格。坐标 (i, j) 表示单元格位于第 i 行,第 j 列。每对相邻的单元格之间有一条道路连接,所有的道路都只能按规定的单一方向行驶。道路方向共有三种情况:
由单元格 (i, j) 驶向单元格 (i + 1, j) ,1 ≤ i < n ,方向向下;
由单元格 (i, j) 驶向单元格 (i, j + 1) ,1 ≤ j < m ,i 是奇数,方向向右;
由单元格 (i, j) 驶向单元格 (i, j − 1) ,1 < j ≤ m ,i 是偶数,方向向左。
每个单元格可能是商铺或者住宅,商铺用 0 表示,住宅用 1 表示。一个 7 × 6 的街区示意图如下,空白单元格为商铺。配送公司需要用货车给每个住宅配送生活用品,货车从单元格 (1, 1) 出发,按道路规定方向行驶,从每一个单元格驶向其相邻的单元格均花费 1 分钟。
请问货车最短需要行驶多少分钟才能完成配送任务?(忽略给每个住宅分配生活用品的时间,不考虑货车的回程)。
【输入】
第 1 行包含 2 个整数 n 和 m ,表示行数和列数。接下来 n 行,每行包含 m 个字符,由 0 和 1 组成,0 代表该单元格为商铺,1 代表该单元格为住宅。 保证单元格 (1, 1) 为商铺。
【输出】
输出 1 行 1 个整数,表示货车完成配送任务需要的最短时间(分钟)。
【输入输出样例1】
transport.in | transport.out |
7 6 010010 010100 001000 000010 000001 000000 100000 | 22 |
【代码】
#include <iostream>
#include <cstring>
using namespace std;
struct Node
{
int l, r;
}a[210];
char s[210];
int main()
{
int n, m;
cin >> n >> m;
int last = 1;
for (int i = 1; i <= n; i ++)
{
scanf("%s", s+1);
int l = 1, r = m;
while (r >= 1 && s[r] != '1') r --;
while (l <= m && s[l] != '1') l ++;
a[i] = {l, r};
if (l != m+1) last = i;
}
int ans = last-1, pos = 1;
for (int i = 1; i <= n; i ++) {
if (a[i].l == m+1) continue;
if (i & 1) {
if (pos > a[i].l) {ans += pos - a[i].l; pos = a[i].l;}
ans += abs(a[i].r - pos);
pos = a[i].r;
}
else {
if (pos < a[i].r) {ans += a[i].r - pos; pos = a[i].r;}
ans += abs(a[i].l - pos);
pos = a[i].l;
}
// printf("ans: %d, pos: %d\n", ans, pos);
}
cout << ans << endl;
return 0;
}
T3、乒乓球
【问题描述】
m个相同的乒乓球分到 n个不同的盒子中,已知第 i个盒子最多能容纳 ai个乒乓球。所有乒乓球要求必须分完,求分配方案数。 答案对 1000000007取模。
【输入】
第一行输入两个正整数 n 和 m。
之后 n 行,每行两个整数 l_i 和 r_i,描述一个区间。
输入共2 行。
第 1行 2个整数,n,m,表示盒子的数量和乒乓球数量。
第 2行 n个整数,a1,a2,……,an ,用空格隔开,表示每个盒子最多可容纳乒乓球的数量。
【输出】
输出 1行 1个整数,表示分配方案数,答案对 1000000007取模。
【输入输出样例 1】
tennis.in | tennis.out |
3 5 2 2 3 | 6 |
说明: 6种方案分别是: (0,2,3),(1,1,3),(1,2,2),(2,0,3),(2,1,2),(2,2,1)每种方案 按盒子顺序给出数量。
【代码】
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1000000007;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> dp(m + 1, 0);
dp[0] = 1; // 0涓箳涔撶悆鏈変竴绉嶆斁娉?
for (int i = 0; i < n; i++) {
vector<int> prefix_sum(m + 1, 0);
prefix_sum[0] = dp[0];
for (int j = 1; j <= m; j++) {
prefix_sum[j] = (prefix_sum[j - 1] + dp[j]) % MOD;
}
for (int j = 0; j <= m; j++) {
if (j > a[i]) {
dp[j] = (prefix_sum[j] - prefix_sum[j - a[i] - 1] + MOD) % MOD;
} else {
dp[j] = prefix_sum[j];
}
}
}
cout << dp[m] << endl;
return 0;
}