[英]Don't know how to use a hash table to solve a problem
我必須使用 hash 表解決以下問題(在 C 中)(我假設使用 hash 表,因為我們現在正在研究 hash 表):
輸入的第一行有 2 個數字: n , m
接下來,我們輸入n行m個數字。 (所以一個n*m矩陣)我們必須從左上角到右下角 go (只能通過向南或向東移動)。 我們穿過的每個單元格要么將單元格中的數字添加到變量“ s ”中,要么減少它。 因此,如果我們用 -5 遍歷一個單元格,我們將得到s-5 ,如果我們用 +3 遍歷一個單元格,我們將得到s+3 。 最開始, s是左上角的數字,總是>0。 另一個規則是我們不能遍歷數字為 0 的單元格。此外,每次離開單元格時都必須減 1,因此每次離開單元格時都會得到s-1 。 output必須是到達右下角后可以得到的最大s 。 這是輸入/輸出的示例:
保證至少有一條到右下角的路徑最終將給出至少等於 1 的s ,因此如果最終s為負數,則該路徑肯定是錯誤的。
我很難解決這個問題(特別是使用 hash 表),所以非常感謝任何幫助。 另外,有沒有其他更有效的解決方法?
這似乎是一個非常簡單的動態規划問題。
讓左上角為索引(0, 0)
和右下角(n - 1, m - 1)
,讓arr[i][j]
為(i, j)
position 中的數字。 然后對於所有i, j
使得0 <= i < n
和0 <= j < m
,將f(i, j)
定義為從s
(0, 0)
到 position (i, j)
,如果這是不可能的,則為-1
。
如果previousS = INT_MIN
或valueInCell = 0
則將combine(previousS, valueInCell)
定義為INT_MIN
,否則將previousS + valueInCell - 1
為。
然后我們看到以下是真的:
f(0, 0) = arr[0, 0]
f(i, 0) = combine(f(i - 1, 0), arr[i][0])
對於所有1 <= i < n
f(j, 0) = combine(f(j - 1, 0), arr[0][j])
對於所有1 <= j < m
f(i, j) = combine(max(f(i - 1, j), f(i, j - 1)), arr[i][j])
對於所有1 <= i < n
和1 <= j < m
特別是,我們正在尋找f(n - 1, m - 1)
。
現在這是一個遞歸算法,但是遞歸將非常低效,因為我們每次最多可以進行 2 次遞歸調用。 因此,我們將定義一個數組f[i][j]
來保存f
的值。
int combine(int previous_s, int value_in_cell) {
return previous_s == INT_MIN || value_in_cell == 0 ? INT_MIN : previous_s + value_in_cell - 1;
}
int max(int i, int j) {
return i > j ? i : j;
}
int computeS(int n, int m, int** arr) {
int** const f = malloc(n * sizeof *f);
int** const end_f = f + n;
for(int** j = f; j < end_f; j++) {
*j = malloc(m * sizeof **j);
}
f[0][0] = arr[0][0];
for(int i = 1; i < n; i++) {
f[i][0] = combine(f[i - 1][0], arr[i][0]);
}
for(int j = 1; j < m; j++) {
f[0][j] = combine(f[0][j - 1], arr[0][j]);
}
for(int i = 1; i < n; i++) {
for(int j = 1; j < m; j++) {
f[i][j] = combine(max(f[i - 1][j], f[i][j - 1]), arr[i][j]);
}
}
int const ret_val = f[n - 1][m - 1];
for(int** j = f; j < end_f; j++) {
free(*j);
}
free(f);
return ret_val;
}
如您所見,不需要 hash 表。
執行 I/O 的代碼:
int main() {
int n, m;
scanf("%d%d", &n, &m);
int** const arr = malloc(n * sizeof *arr);
int** const end_arr = arr + n;
for(int** j = arr; j < end_arr; j++) {
*j = malloc(m * sizeof **j);
for(int* k = *j; k < *j + m; k++) {
scanf("%d", k);
}
}
printf("%d\n", computeS(n, m, arr));
for(int**j = arr; j < end_arr; j++) {
free(*j);
}
free(arr);
return 0;
}
正如馬克提到的,這是動態規划問題。 所以這個問題與hash表無關。 現在,由於馬克的回答有點難以理解,我將嘗試解釋我的解決方案。 給定的問題類似於標准矩陣路徑優化問題,但有兩個有趣的轉折。
0 valued cells
。0 valued cells
與中間dp
矩陣中的單元格。 因此,為了解決上述問題,我們需要分別存儲原始0 valued cells
的索引。 最簡單的方法是創建另一個參考矩陣並標記0 valued cells
。
現在,我們應用簡單的動態規划技術。
dp[i][j]= dp[i][j] + max(dp[i-1][j],dp[i][j-1]) - 1;
if (zeroed[i][j] == 1)
即是一個0 valued cell
,則忽略該單元格。if (zeroed[i-1][j] == 1)
然后忽略頂部單元格的加法。if (zeroed[i][j-1] == 1)
然后忽略左單元格的加法。dp[row-1][col-1]
是優化的答案。這就是我們解決這個問題的方法。 如果你仍然覺得它很難,那么你需要學習動態規划。 程序代碼:
#include<iostream>
using namespace std;
int zeroed[50][50]; //for reference of 0 valued cells
int main(){
int dp[50][50];
int row,col,value;
cin>>row>>col;
/*=========initializing matrix========*/
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
cin>>value;
dp[i][j]=value;
if(value == 0){
zeroed[i][j]=1; //marking 0 valued cell
}
}
}
/*==========applying dynamic programming=====*/
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
if(zeroed[i][j]== 1){
continue; //just ignore this cells
}
if(i>0 && j>0){
if(zeroed[i-1][j] !=1 && zeroed[i][j-1]!=1){
dp[i][j]+=max(dp[i-1][j],dp[i][j-1]) - 1;
}else if(zeroed[i-1][j]!=1){
dp[i][j]+= dp[i-1][j] - 1;
}else if(zeroed[i][j-1]!=1){
dp[i][j]+=dp[i][j-1] - 1;
}
//ignore other cases
}else if(i>0){
if(zeroed[i-1][j]!=1){
dp[i][j]+=dp[i-1][j] - 1;
}
//ignore other cases
}else if(j>0){
if(zeroed[i][j-1]!=1){
dp[i][j]+=dp[i][j-1] - 1;
}
//ignore other cases
}
}
}
cout<<dp[row-1][col-1];//max s
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.