F 小帆帆走迷宫
链接:https://ac.nowcoder.com/acm/contest/642/F
来源:牛客网
题目描述
小帆帆被困在一个 NxN 的方格矩阵迷宫,每个格子中都有一个整数 A[i][j]。小帆帆从迷宫起点(左上角)格子 A[1][1]开始走,每一步可以向右或向下移动,目标是移动到迷宫的出口右下角 A[N][N]。 小帆帆需要支付的费用包括路径中经过的所有格子中的整数之和,以及改变移动方向需要支付的费用。 小帆帆第一次改变方向的费用是 1,第二次的费用是 2,第三次的费用是 4,…… 第 K 次的费用是2?−1。 请你帮小帆帆算出要离开迷宫的最小花费。
输入描述:
第一行一个整数T,代表测试数据组数。每一组第一行一个整数N。 (1 ≤ N ≤ 100)以下N行每行N个整数,代表矩阵A。 (1 ≤ A[i][j] ≤ 100)
输出描述:
从起点到终点路径的最小花费。
示例1
输入
2
1
10
3
1 3 5
1 1 2
5 1 1
输出
10
9
枚举每个格点对应可由哪些格点得来,然后枚举上个结点的状态,由于转弯次数过多所以对于过多的情况直接不用枚举
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 110;
int mp[maxn][maxn];//地图
int f[maxn][maxn][30][2];
//记录到达某个点的代价,转弯的次数,当前的方向
//0表示向下走,1表示向右走
int w[25];
int main(){
int T;
cin >> T;
w[0] = 1;
for (int i = 1; i <= 25; i++)
w[i] = w[i - 1] * 2;
while (T--){
int n;
cin >> n;
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n; j++)
cin >> mp[i][j];
f[1][1][0][0] = mp[1][1];
f[1][1][0][1] = mp[1][1];
for (int i = 1; i <= n;i++)
for (int j = 1; j <= n; j++){
for (int k = 0; k <= 20; k++){
f[i][j][k][0] = min(f[i][j][k][0], f[i][j-1][k][0] + mp[i][j]);//上个格子没转弯向下走
f[i][j][k + 1][0] = min(f[i][j][k + 1][0], f[i][j - 1][k][1] + w[k] + mp[i][j]);
//上面个格子转弯后到达这个点
}
for (int k = 0; k <= 20; k++){
f[i][j][k][1] = min(f[i][j][k][1], f[i - 1][j][k][1] + mp[i][j]);
f[i][j][k + 1][1] = min(f[i][j][k + 1][1], f[i - 1][j][k][0] + w[k] + mp[i][j]);
//同理向右的情况
}
}
int sum = 0x3f3f3f3f;
for (int i = 0; i <= 20; i++)//枚举转弯次数为几时的总代价,取最小
sum = min({ sum, f[n][n][i][0], f[n][n][i][1] });
cout << sum << endl;
}
return 0;
}
I杨主席发糖
题目描述
19 年校赛的结果已经出炉,为了对大家的积极参与表示感谢,杨主席准备拿出他的工资给大家发福利。 所有参赛选手排成一排,每位同学都对于有一个量化的得分(当然,得分越高越好)。杨主席已事先知道选手们的排队顺序以及个人的得分,他将一个一个给大家发糖。 杨主席是个有原则的男人,但他原则也是有限的。所谓有原则是指:分数高的一定比分数低的能拿到更多的糖果且分数 一样的拿到的糖果一样多;所谓原则是有限的又是指:刚刚说的原则仅对排队中相邻的两人生效,且允许有人拿不到糖果(杨主席是个穷逼)。 杨主席并不想多花一分钱买额外的糖,于是他想知道在各种情况下最少需要购入几块糖。
输入描述:
首先是一个整数T,表示数据输入的组数,T<=20。对于每组数据,有两行:(1)一个整数n,表示队列中的人数,0 < n <= 1000。(2)n个整数a[0] … a[n-1],表示按队列顺序每个人的得分,注意可能会有同分的情况,保证a[i]是int类型的。
输出描述:
对应T行,每行即对应每组输入的最少购入糖数结果。
示例1
输入
2
6
12 13 14 5 10 13
6
2 2 2 2 2 2
输出
6
0
对于当前位置用数组分别前后扫一遍记录相连的有几个比自己小的,最后用数组遍历取每个位置的最大值求和
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int f[maxn], g[maxn], a[maxn];
int main(){
int T;
cin >> T;
while (T--){
int n;
cin >> n;
memset(f, 0, sizeof f);
memset(g, 0, sizeof g);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 2; i <= n; i++){
if (a[i] == a[i - 1])
f[i] = f[i - 1];
else if (a[i] > a[i - 1])
f[i] = f[i - 1] + 1;
//else f[i] = 0;
}
for (int i = n - 1; i >= 1; i--){
if (a[i] > a[i + 1])
g[i] = g[i + 1] + 1;
else if (a[i] == a[i + 1])
g[i] = g[i + 1];
//else g[i] = 0;
}
int sum = 0;
for (int i = 1; i <= n; i++){
sum += max(g[i], f[i]);
}
cout << sum << endl;
}
return 0;
}
L.实际问题
题目描述
本题的出题人在实习(摸鱼)中遇到了一个非常有意思的问题,这个问题的核心即需要枚举“组合”。 组合即数学上的“C”的概念,我们知道 C(x,y)=y!/x!/(y-x)! 如果我们想枚举 C(3,4),我们有: 1 2 3 1 2 4 1 3 4 2 3 4 这道题就是这个意思,当然为了简化输出,我们只要你给出按顺序的第 k 个组合即可,如 C(3,4)的第 3 个是:1 3 4 注意组合内部是无序的,但是我们希望得到一个递增顺序的结果,即结果是 1 3 4,而非诸如 1 4 3 之流。
输入描述:
首先是一个整数T,表示数据输入的组数,T<=10。对于每组数据,一行三个数n,m,k:欲求C(m,n)的第k个组合。保证n<=100000,m<=n,k<=1000000,k<=C(m,n)。
输出描述:
对应T行,每行即结果。
输入
2
6 3 10
100 5 1000
输出
1 5 6
1 2 3 14 99
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll num[maxn];
int n, m, k, flag;
int cnt;
void dfs(int x, int y){//y为这组的第几个
if (flag) return;
if (y == m+1){
cnt++;
if (cnt == k){
for (int i = 1; i < m; i++)
cout << num[i] << " ";
cout << num[m] << endl;
flag = 1;
}
return;
}
for (int i = x; i <= n - m + y; i++){//选下一个或者不选
num[y] = i;
dfs(i + 1, y + 1);//选过不能重复选 i+1
if (flag) return;
}
}
int main(){
int T;
cin >> T;
while(T--)
{
cin >> n >> m >> k;
memset(num, 0, sizeof num);
flag = 0;
cnt = 0;
dfs(1, 1);
}
return 0;
}