簡體   English   中英

不知道怎么用hash表解決一個問題

[英]Don't know how to use a hash table to solve a problem

我必須使用 hash 表解決以下問題(在 C 中)(我假設使用 hash 表,因為我們現在正在研究 hash 表):

輸入的第一行有 2 個數字: nm

接下來,我們輸入nm個數字。 (所以一個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 < n0 <= j < m ,將f(i, j)定義為從s (0, 0)到 position (i, j) ,如果這是不可能的,則為-1

如果previousS = INT_MINvalueInCell = 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 < n1 <= 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表無關。 現在,由於馬克的回答有點難以理解,我將嘗試解釋我的解決方案。 給定的問題類似於標准矩陣路徑優化問題,但有兩個有趣的轉折。

  1. 解決方案路徑不能包含0 valued cells
  2. 以上點也是一個標准問題。 但這就是轉折點。 由於單元格具有 integer 值。 由於先前的加法和減法運算,很難區分原始0 valued cells與中間dp矩陣中的單元格。

因此,為了解決上述問題,我們需要分別存儲原始0 valued cells的索引。 最簡單的方法是創建另一個參考矩陣並標記0 valued cells

現在,我們應用簡單的動態規划技術。

  1. dp[i][j]= dp[i][j] + max(dp[i-1][j],dp[i][j-1]) - 1;
  2. if (zeroed[i][j] == 1)即是一個0 valued cell ,則忽略該單元格。
  3. if (zeroed[i-1][j] == 1)然后忽略頂部單元格的加法。
  4. if (zeroed[i][j-1] == 1)然后忽略左單元格的加法。
  5. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM