1. 程式人生 > >hdu1978 How many ways(記憶化搜尋)

hdu1978 How many ways(記憶化搜尋)

題意:中文題。

思路:注意這題題中說“當機器人選擇了一條可行路徑後,當他走到這條路徑的終點時,他將只有終點所標記的能量”。剛開始這條件我就看了半天,這句話中明確指出大的能量轉移(不包括每走一步的能量減一)只有一個條件可以觸發,那就是到達終點,其他沒說明的就表明無法觸發。(有異議的歡迎撕逼,這的確是題的問題)。然後就開始寫,每次dfs傳遞能量值pow,每遞迴一次能量減一,中間一個if就可以搞定。然而怎麼也搞不出答案,後來手算了幾遍發現沒問題,這是題意理解錯了,然後看了別人題解才發現是題錯了。。

一個最大的變化就是所到路徑上的點也可以發生能量轉移,接著就在原程式上改。我用的方法是一步一步走判斷,加了這個條件後dfs裡就相當於有兩個dfs序列執行,問題就來了,哪個dfs放在前面?執行了一個dfs就會對其餘節點產生變化,而另一個是要求變化以前的值。無奈,想不出好法子,看了別人的方法。

這種搜尋方式相當於列舉吧,列舉所有的能量值,當然是加了這種變化後才有這種效果。為毛我就沒想出來呢???[尼克揚的微笑]

這也給了我個啟示,一個好的搜尋方式是做出搜尋題的關鍵。

#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

const int N = 105;
const int INF = 0x3f3f3f3f;

int n, m, G[N][N], dp[N][N];

bool check(int x, int y)
{
    if(x>=1 && x<=n && y>=1 && y<=m) return true;
    else return false;
}

int dfs(int x, int y)
{
    if(dp[x][y] > 0) return dp[x][y];
    else
    {
        if(x==n && y==m) return 1;
        for(int i = 0; i <= G[x][y]; i++)
        {
            for(int j = 0; j <= G[x][y]; j++)
            {
                if(i==0 && j==0) continue;
                if(check(x+i, y+j) == false) continue;
                if(i+j > G[x][y]) continue;//沒能量走不到
                dp[x][y] = (dp[x][y]+dfs(x+i, y+j))%10000;//注意這裡必須先與求一下餘,處理比較大的數耗時較多,否則超時,那後面就不用再求了
            }
        }
    }
    return dp[x][y];
}


int main()
{
 //   freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%d", &G[i][j]);
        memset(dp, 0, sizeof(dp));
        printf("%d\n", dfs(1, 1));
    }
    return 0;
}


再貼上我的失敗程式碼吧,就如上面所說:

#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>

using namespace std;

typedef long long LL;

const int N = 105;
const int INF = 0x3f3f3f3f;

int n, m, G[N][N], dp[N][N];
int dir[2][2] = {{1, 0}, {0, 1}};

bool check(int x, int y)
{
    if(x>=1 && x<=n && y>=1 && y<=m) return true;
    else return false;
}

int num = 0;

int dfs(int x, int y, int pow)
{
    if(dp[x][y] > 0) return dp[x][y];
    else
    {
        if(((x==n)&&(y==m)))//到達終點
        {
            printf("[%d]\n", num++);
            dp[x][y] = 1;
            return 1;
        }
        int sum = 0;
        //dp[x][y] = 0;
        for(int i = 0; i < 2; i++)
        {
            int xx = x+dir[i][0];
            int yy = y+dir[i][1];
            if(check(xx, yy))//如果找到新節點
            {
                if(pow == 0)
                {
                    sum+=dfs(xx, yy, G[xx][yy]);
                }
                else
                {
                    sum+=dfs(xx, yy, pow-1);
                    sum+=dfs(xx, yy, G[xx][yy]);//序列執行
                }
            }
        }
        dp[x][y] = sum;
        return dp[x][y];
    }
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%d", &G[i][j]);
        memset(dp, 0, sizeof(dp));
      //  pow = G[1][1];
        printf("%d\n", dfs(1, 1, G[1][1]));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= m; j++)
            {
                printf("%d ", dp[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}