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;
}