1. 最短区间 - 双指针
现在给定一个整数s
以及一个长度为n的整数数列a[0],a[1],a[2],a[3]....a[n-1]
(全为正数),
请你求出总和不小于s的连续子序列的长度的最小值。如果解不存在,则输出0
。
输入
第一行:两个整数,表示 s 与 n,其中1≤s≤10^9,1≤n≤500000;
第二行:n个用空格隔开的整数,表示 a[0] a[1] ... a[n-1],其中对于任意a[i]有1≤a[i]≤10^9。
输出
输出总和不小于s的连续子序列长度的最小值。
如果解不存在,则输出0。
输入样例
50 20
10 8 9 3 11 8 5 1 1 1 1 20 8 9 11 4 13 22 9 6
输出样例
4
Code
#include<bits/stdc++.h>
#define MAXN 500005
#pragma GCC optimize(2)
using namespace std;
using ull = unsigned long long;
ull arr[MAXN];
int main() {
ios::sync_with_stdio(false);
int s, n;
cin >> s >> n;
for (int i = 0; i < n; i++) cin >> arr[i];
ull sum = 0;
int i = 0, j = -1, minLength = INT_MAX;
while (j++ < n) {
while (sum >= s) {
minLength = min(minLength, j - i);
sum -= arr[i++];
}
sum += arr[j];
}
cout << (minLength == INT_MAX ? 0 : minLength);
return 0;
}
2. 池塘数量 - DFS
最近大雨连连,积水把农夫约翰的农田里,很多地方都变成了水池。农夫约翰的池塘可以被表示为一个n
行,每行有m
个方格的矩形。每个方格要么是'W'
要么是'.'
。农夫约翰想要统计他的农田里有多少个池塘,一个池塘是指一个由'W'
方格组成的极大连通块。这里认为两个方格相邻当且仅当他们在上
、下
、左
、右
、左上
、左下
、右上
、右下
这八个方向中的某一个相邻。
给出农夫约翰的农田,帮他统计有多少个池塘。
输入
第一行两个正整数n和m 接下来n行,每行一个长为m的字符串表示这一行的农田
30%的数据: 1<=n,m<=20 60%的数据: 1<=n,m<=60 100%的数据: 1<=n,m<=300
输出
一行一个整数表示农夫约翰的农田中的池塘数量
输入样例
12 8
...W.WWW
WWW..W..
W.WW.WWW
..W..WWW
WW..WWWW
.WWW..W.
.W....WW
........
.WW.WW..
W.WWWW..
...W...W
...W..WW
输出样例
3
Code
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
bool grid[305][305];
int n, m;
const vector<pair<int, int>> DIR = {{0, 1}, {0, -1}, {1, 0}, {-1, 0},
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
void dfs(int x, int y) {
if (x < 0 || y < 0 || x >= n || y >= m || !grid[x][y]) return;
grid[x][y] = false;
for (auto&[dx, dy]:DIR) dfs(x + dx, y + dy);
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
string s;
for (int i = 0; i < n; i++) {
cin >> s;
for (int j = 0; j < m; j++) grid[i][j] = (s[j] == 'W');
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j]) {
ans++;
dfs(i, j);
}
}
}
cout << ans;
return 0;
}
3. 挑选数字 - 回溯&剪枝
给出n
个正整数,从中挑选若干个,使得他们的和为m
。如果存在多个,输出排序后字典序最小的一组。如果没有找到任何一组,输出"No Solution"
。
输入
第一行:2个数n,m(1≤n≤30, 1≤m≤10^8)
第2-n+1行:每行1个数ai(1≤ai≤10^7)
对于50%的数据,1≤n≤20;
对于100%的数据,1≤n≤30, 1≤m≤10^8,1≤ai≤10^7。
输出
输出共1行,对应选中的数字,中间用空格分隔。如果没有找到任何一组,输出"No Solution"。
输入样例
5 15
1
3
5
7
9
输出样例
1 5 9
代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n, m;
vector<int> path;
int arr[31], rsum[31];
bool backtracking(int iStart, int target) {
if (target == 0) return true;
for (int i = iStart; i < n; ++i) {
if (target < arr[i] || target > rsum[i]) break;
path.push_back(arr[i]);
if (backtracking(i + 1, target - arr[i])) return true;
path.pop_back();
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> arr[i];
sort(arr, arr + n);
for (int i = n - 1; i >= 0; --i) rsum[i] = rsum[i + 1] + arr[i];
if (backtracking(0, m)) {
for (int i : path) cout << i << ' ';
} else {
cout << "No Solution";
}
return 0;
}
4. 交友 - BFS
一场舞会中有n个人(编号0到n−1),小A和小B也在其中(编号为0和1)。这n个人有一些是朋友关系,有一些不是。为了让小A和小B成为朋友,不如跳舞!我们认为当两个人有一个共同的朋友时,这两个人可以跳一支舞,并成为朋友。问最少要跳几场舞使得小A和小B成为朋友。数据保证a[i,j] = a[j,i]。
数据范围:1<=n<=100
输入
第一行一个整数n,表示舞会中的人数。 接下来为一个n*n的字符矩阵,其中第i行第j列(i,j都从0开始标号)的字母为'Y'当且仅当编号为i,j的两人是朋友,字母为'N'当且仅当编号为i,j的两人不是朋友。
输出
输出仅一行一个整数ans表示最少需要跳舞的场数,如果两人已经是朋友则输出0,如果两人无论如何也无法成为朋友,则输出-1。
输入样例
6
NNYYNN
NNNNYY
YNNNYN
YNNNNY
NYYNNN
NYNYNN
输出样例
2
代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
int n;
bool graph[105][105];
bool visited[105];
int bfs() {
queue<int> q;
int dist = -1;
q.push(0);
while (!q.empty()) {
int size = q.size();
while (size--) {
int next = q.front();
visited[next] = true;
q.pop();
if (next == 1) return dist;
for (int i = 0; i < n; i++) {
if (graph[next][i] && !visited[i]) q.push(i);
}
}
dist++;
}
return -1;
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
string s;
for (int i = 0; i < n; i++) {
cin >> s;
for (int j = 0; j < n; j++) graph[i][j] = (s[j] == 'Y');
}
cout << bfs();
return 0;
}
5. 加油站 - 贪心
一辆卡车,初始时距离终点L
,油量为P
,在起点到终点途中有n
个加油站,每个加油站油量有限,而卡车的油箱容量无限,卡车在行车途中,每走一个单位的距离消耗一个单位的油量,给定n
个加油站距离起点的距离A[i]
以及油存储量B[i]
。问卡车是否能到达终点,如果可达,最少需要加多少次油,否则输出-1
。输入不保证有序。
1<=n<=10000
; 1<=L<=1000000
; 1<=P<=1000000
;1<=A[i]<L
,1<=B[i]<=100
。
输入
第一行三个数L,P,n,以空格隔开,分别表示起点到终点的距离、现在的油量、中途加油站数; 之后n行,每行两个数A[i]和B[i],以空格隔开,表示该加油站到起点的距离和油存储量。
输出
输出一个数,表示最少的加油次数。
输入样例
100 15 2
15 75
90 25
输出样例
2
代码
#include<iostream>
#include<queue>
#include<algorithm>
#define MAXN 10005
#pragma GCC optimize(2)
using namespace std;
int L, P, n;
pair<int, int> A[MAXN];
int solve() {
priority_queue<int> pue;
for (int i = 0; i <= n; i++) {
while (A[i].first > P) {
if (pue.empty()) return -1;
P += pue.top();
pue.pop();
}
pue.push(A[i].second);
}
return n + 1 - pue.size();
}
int main() {
ios::sync_with_stdio(false);
cin >> L >> P >> n;
for (int i = 0; i < n; ++i) cin >> A[i].first >> A[i].second;
A[n] = {L, 0}; // 视终点为加油站
sort(A, A + n + 1, [](const pair<int, int> &lo, const pair<int, int> &hi) {
return lo.first < hi.first;
});
cout << solve();
return 0;
}
6. 染车 - DFS
n×m
的棋盘上某些位置放着几个车,两个车互相攻击当且仅当如下条件全部满足:
1、两车同行或同列;2、两车之间没有其他车;3、两车颜色不同。
现在给你这些车的位置,请你用尽量多的颜色给它们染色,使得任意两辆车都不互相攻击。
数据范围:1<=n, m<=20
输入
读入第一行包含两个整数n, m,表示棋盘的行数和列数
接下来n行m列,描述整个棋盘。棋盘中共包含两类字符,字符.表示空地,字符R表示车。
对于42.5%的数据,1≤n,m≤5;
对于87.5%的数据,1≤n,m≤10;
对于100%的数据,1≤n,m≤20;
输出
输出共一行,表示你能保证车不互相攻击的前提下,能用的最多的颜色数。
输入样例
3 4
.R.R
R.R.
.R.R
输出样例
2
代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
bool graph[20][20];
int n, m, ans = 0;
void dfs(int x, int y) {
graph[x][y] = false;
for (int i = 0; i < n; ++i) {
if (graph[i][y]) dfs(i, y);
}
for (int j = 0; j < m; ++j) {
if (graph[x][j]) dfs(x, j);
}
}
int main() {
ios::sync_with_stdio(false);
string s;
cin >> n >> m;
for (int i = 0; i < n; ++i) {
cin >> s;
for (int j = 0; j < m; ++j) graph[i][j] = (s[j] == 'R');
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (graph[i][j]) {
ans++;
dfs(i, j);
}
}
}
cout << ans;
return 0;
}