1. 程式人生 > >HDU-1428-漫步校園 (bfs與dfs與記憶化搜尋(dp))

HDU-1428-漫步校園 (bfs與dfs與記憶化搜尋(dp))

原題連結:
http://acm.hdu.edu.cn/showproblem.php?pid=1428
LL最近沉迷於AC不能自拔,每天寢室、機房兩點一線。由於長時間坐在電腦邊,缺乏運動。他決定充分利用每次從寢室到機房的時間,在校園裡散散步。整個HDU校園呈方形佈局,可劃分為n*n個小方格,代表各個區域。例如LL居住的18號宿舍位於校園的西北角,即方格(1,1)代表的地方,而機房所在的第三實驗樓處於東南端的(n,n)。因有多條路線可以選擇,LL希望每次的散步路線都不一樣。另外,他考慮從A區域到B區域僅當存在一條從B到機房的路線比任何一條從A到機房的路線更近(否則可能永遠都到不了機房了…)。現在他想知道的是,所有滿足要求的路線一共有多少條。你能告訴他嗎?
Input
每組測試資料的第一行為n(2=<n<=50),接下來的n行每行有n個數,代表經過每個區域所花的時間t(0<t<=50)(由於寢室與機房均在三樓,故起點與終點也得費時)。
Output
針對每組測試資料,輸出總的路線數(小於2^63)。
Sample Input
3
1 2 3
1 2 3
1 2 3
3
1 1 1
1 1 1
1 1 1
Sample Output
1
6
題意:
中文題
題解:
對於這道題目
(我的TLE思路)
直接用dfs深搜搜索出每一條路線的耗時,然後利用map記錄下每一個耗時出現的次數,最後輸出耗時最短的次數。
(TLE的記憶化搜尋思路)
知道了也要利用記憶化搜尋後,我還是不忍心刪掉這麼多的dfs深搜,於是就用了dfs先找出了每一個點距離終點的距離,之後在用了一次dfs2深搜得到最短時間的耗時,結果還是TLE了。
(正確的記憶化搜尋)
先利用bfs廣搜得到每一個點到終點的最短距離,之後再利用dfs找出出現最短耗時的次數。(具體操作見程式碼)
附上AC程式碼:

#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
struct node{
    int x, y;
};//定義結構體,方便bfs時棧的需要
node S;
int n;
int dir[4][2]={1,0,0,1,-1,0,0,-1};//方向
long long st[55][55];//初始表
long long dp[55][55];//每一個點到終點的最短距離
long long cnt[55][55];//該點到終點走最短距離的線路

void bfs()
{
    queue<node> que;
    S.x = n, S.y = n;
    memset(dp, -1, sizeof(dp));
    dp[n][n] = st[n][n];
    que.push(S);
    while(!que.empty()){
        node u = que.front();
        que.pop();
        int x = u.x, y = u.y;
        for (int i = 0; i < 4; i++){
            int nx = x + dir[i][0];
            int ny = y + dir[i][1];
            if (nx<=0||nx>n||ny<=0||ny>n) continue;
            if (dp[nx][ny] == -1 || dp[x][y] +st[nx][ny] < dp[nx][ny])//找出最短距離
            {
                dp[nx][ny] = dp[x][y] + st[nx][ny];
                que.push((node){nx, ny});
            }
        }
    }
}
long long dfs(int x,int y)
{
    if (cnt[x][y]) return cnt[x][y];
    for (int i = 0; i < 4; i++){
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (nx<=0||nx>n||ny<=0||ny>n) continue;
        if (dp[nx][ny] < dp[x][y])//只要是比該點到終點的最短距離小的(根據題意得到的,這點容易迷糊)
            cnt[x][y] += dfs(nx, ny);
    }
    return cnt[x][y];

}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                scanf("%lld",&st[i][j]);
            }
        }
        memset(dp,0,sizeof(dp));
        memset(cnt,0,sizeof(cnt));//重置
        bfs();
        cnt[n][n]=1;
        printf("%lld\n",dfs(1,1));
        //讀者可以輸出最終解果,更清楚的理解

        /*for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                printf("%lld ",cnt[i][j]);
            puts("");
        }
        */
    }
    return 0;
}

歡迎評論!