第一题 Shaking hands
题意:你邀请n个好友聚会,好友之间互相认识的要喝酒,你和每个好友也要喝酒,问要准备多少杯酒。
题解:答案为
ans=2∗n+bitmat其中 bitmat 表示关系矩阵中1的个数。
#include <bits/stdc++.h>
int main() {
int n, a;
while (~scanf(" %d", &n)) {
int sum = n << 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
scanf(" %d", &a);
sum += a;
}
}
printf("%d\n", sum);
}
return 0;
}
第二题 Gunner II
题意:给一排树的高度,分别为 h[1],h[2],...,h[n] ,JB大哥站在最左边,每次给个高度 q[i] ,问最近的高度为 q[i] 的树编号是多少。
题解:考虑不同高度的树,对某个高度的树,维护一颗平衡二叉树,同时所有高度也用一颗平衡二叉树维护,于是查找复杂度可为 log(m)+log(n) ,其中 m,n 分别表示不同高度的个数和该高度下树的棵数。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
map<int, set<int> > S;
map<int, set<int> >::iterator it;
set<int> toInsert;
while (~scanf(" %d %d", &n, &m)) {
S.clear();
int a;
for (int i = 1; i <= n; ++i) {
scanf(" %d", &a);
if ((it = S.find(a)) != S.end()) {
(it->second).insert(i);
//printf("push height %d\n", a);
} else {
toInsert.clear();
toInsert.insert(i);
S.insert(make_pair(a, toInsert));
//printf("new to height %d\n", a);
}
}
for (int i = 1; i <= m; ++i) {
scanf(" %d", &a);
if ((it = S.find(a)) == S.end()) {
puts("-1");
} else {
printf("%d\n", *(it->second).begin());
(it->second).erase((it->second).begin());
if ((it->second).empty()) {
S.erase(it);
}
}
}
}
return 0;
}
第三题 Happy birthday
题意:JB大哥吃蛋糕,从左上角一直吃到右下角,但是肚子有个容量 K ,问最多可以吃多少。
题解:简单dp,定义状态
dp[i][j][k] 表示在位置 (i,j) 能否吃到 k 的蛋糕。转移:其中 cake[i][j] 表示位置 (i,j) 处的蛋糕。其实也就是考虑能否直接从状态 dp[i][j−1][k] 或者 dp[i−1][j][k] 转移而来,如果可以,那么只需要在 (i,j) 处选择不吃蛋糕即可,否则,再考虑是否可以从状态 dp[i][j−1][k−cake[i][j]] 或者 dp[i−1][j][k−cake[i][j]] 转移,即留下一个容量为当前位置蛋糕量的空间(当然,前提是 k≥cake[i][j] )。dp[i][j][k]=dp[i−1][j][k]∨dp[i][j−1][k]∨[k>=cake[i][j]∧(dp[i][j−1][k−cake[i][j]]∨dp[i−1][j][k−cake[i][j]])]
初始化:dp[i][j][0]1≤i≤n,1≤j≤n =true,dp[i][j][k]1≤i≤n,1≤j≤n,1≤k≤K =false
#include <bits/stdc++.h>
using namespace std;
const int MAX = 107;
int cake[MAX][MAX];
bool dp[MAX][MAX][MAX];
int main() {
int n, m, K;
while (~scanf(" %d %d %d", &n, &m, &K)) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf(" %d", &cake[i][j]);
}
}
memset(dp, false, sizeof(dp));
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
dp[i][j][0] = true;
}
}
//dp[i][j][k]: if he can eat k(g) at position(i, j)
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= K; ++k) {
if (dp[i][j][k]) {
dp[i][j + 1][k] = dp[i + 1][j][k] = true;
if (k + cake[i][j + 1] <= K) {
dp[i][j + 1][k + cake[i][j + 1]] = true;
}
if (k + cake[i + 1][j] <= K) {
dp[i + 1][j][k + cake[i + 1][j]] = true;
}
}
}
}
}
for (int i = K; i >= 0; --i) {
if (dp[n][m][i]) {
printf("%d\n", i);
break;
}
}
}
return 0;
}
本文解析了三道经典编程题目,包括Shakinghands问题、GunnerII问题以及Happybirthday问题。针对每道题目,提供了详细的题意说明及解题思路,并附带C++代码实现。

被折叠的 条评论
为什么被折叠?



