HDU-1428(记忆化搜索)

Problem Description
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
 

思路:
这题再加上之前的那道老鼠题,算是记忆化搜索的模板题了,现在来学真是没觉得有什么难度,理顺了题目的思路,看了kuangbin大神的AC代码后,凭着思路在脑中复原代码修正后AC了
题目说A->B点的要求是B点到终点的多个距离中,肯定存在一个dis是小于A点所有到终点的距离的,而A点所有到终点的距离中就会包括通过B到达终点的距离————对这种逻辑进行一下总结,就会发现它让你求的就是起点到终点相同长度最短路的条数
知道了这点之后,我们就可以开始计算所有的最短路了
计算最短路就是用Dijkstra,但是这个题这样做就麻烦了,其实这道题目用的方法Dijkstra是相同的,他们实质都是相同的,即每次对选入最短路线集合的点,松弛他的所有邻边。对于原始的Dij而言,我们用的for扫描整个数组,然后找出相邻的边,再对他们进行松弛操作。
都记录了最短距离之后,在递归求得第一个点的答案。

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;

struct node {
    int x,y;
    int d;
};
int n;
int map[57][57];
int dis[57][57];
__int64 dp[57][57];
int vis[57][57];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};

bool operator < (node a,node b) {
    return a.d>b.d;
}

void dfs()
{
    priority_queue<node> que;
    memset(vis,0,sizeof(vis));
    node tmp,next;
    tmp.x = n;
    tmp.y = n;
    tmp.d = map[n][n];
    que.push(tmp);
    while(!que.empty())
    {
        tmp = que.top();
        que.pop();
        if(vis[tmp.x][tmp.y])
            continue; 
        vis[tmp.x][tmp.y] = 1;
        dis[tmp.x][tmp.y] = tmp.d; 
        for(int i = 0;i < 4;i++) {
            next.x = tmp.x+dir[i][0];
            next.y = tmp.y+dir[i][1];
            if(next.x<1||next.x>n||next.y<1||next.y>n||vis[next.x][next.y]) 
                continue;
            next.d = tmp.d + map[next.x][next.y];
            que.push(next);
        }
    }
}

__int64 solve(int x,int y)
{
    if(dp[x][y] != -1) return dp[x][y];
    else {
        node next;
        dp[x][y] = 0;
        for(int i = 0;i < 4;i++) {
            next.x = x+dir[i][0];
            next.y = y+dir[i][1];
            if(next.x<1||next.x>n||next.y<1||next.y>n)
                continue;
            next.d = dis[next.x][next.y];
            if(next.d < dis[x][y]) 
                dp[x][y]+=solve(next.x,next.y);
        }
        return dp[x][y];
    }
}

int main()
{
    while(cin>>n)
    {
        memset(dp,-1,sizeof(dp));
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= n;j++)
                cin>>map[i][j];
        dfs();
        /*测试最小距离 
        cout<<endl<<"~~~"<<endl;
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= n;j++){
                cout<<dis[i][j]<<' ';
                if(j == n)
                    cout<<endl;
            }
        */
        dp[n][n] = 1;
        cout<<solve(1,1)<<endl;
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/immortal-worm/p/4984652.html