NYOJ 564 最优对称路径(湖南省第七届大学生计算机程序设计竞赛)

由题目意思来看,既然是对称的路径,那么我们只需要把左上三角的值与右下三角的值加到左上三角上,然后计算从0,0到对称线上的点计算最短路,这样可以大大减少计算时间。

那么存网格的时候可以用二维数组存放起来,以测试用例存放就是:

2 2 1

2 1 1

2 1 1

然后我们看

第一条,(1,1)—>(1,2)—>(2,2)

第二条,(1,1)—>(2,1)—>(2,2)

第三条,(1,1)—>(1,2)—>(1,3)

这样明显减少了计算量。

在网格中,可以直接用dijkstra算法借助队列(STL中的queue)求出其最短路,这样有了最短路就只差最后一步统计了。

最后一步统计的思想是这样的,首先是搜索方法,对于每个“左下-右上”对称线上的点出发,到(0,0)搜索。

标记一个状态dp[x][y],代表x,y到0,0上的最短路有dp[x][y]条,且dp[0][0]=1;设tx,ty的集合是{(x-1,y),(x+1,y),(x,y+1),(x,y-1)},如果0,0到x,y的最短路径等于0,0到tx,ty的最短路径加上 [x][y]这个点网格的值,那么状态转移方程为的dp[x][y]是四个d[tx][ty]之和,当然前提是tx,ty这些点是合理的,没有超过网格界限。

还有一个最重要的剪枝是,当dp[x][y]这个点已经统计过了,那么无需再次统计,用一个flag[x][y]来表示是否是第一次统计,如果是第一次统计的话那么需要计算,如果不是的话直接返回dp[x][y],因为已经统计好了。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<memory.h>
 4 #include<queue>
 5 using namespace std;
 6 int map[205][205], dis[205][205],d[205][205], n,mins, dir[4][2] = {-1,0,0,1,1,0,0,-1};
 7 bool flag[205][205];
 8 
 9 #define M 1000000009
10 void bfs()
11 {
12     queue<int> q;
13     int i, x, y, x1, y1;
14     x = 1; q.push(x);
15     y = 1; q.push(y);
16     dis[1][1] = map[1][1];
17     while(!q.empty())
18     {
19         x = q.front(); q.pop();
20         y = q.front(); q.pop();
21         for(i = 0; i < 4; ++i)
22         {
23             x1 = x + dir[i][0];
24             y1 = y + dir[i][1];
25             if(map[x1][y1] && dis[x1][y1] > dis[x][y] + map[x1][y1])
26             {
27                 dis[x1][y1] = dis[x][y] + map[x1][y1];
28                 q.push(x1); q.push(y1);
29             }
30         }
31     }
32     mins = dis[1][n];
33     for(i=2; i<n; ++i)
34         if(dis[i][n-i+1] < mins)
35             mins = dis[i][n-i+1];
36 }
37 
38 int dfs(int x,int y)
39 {
40     int i,tx,ty;
41     if(x==1 && y==1return 1;
42     if(flag[x][y]) return d[x][y];  
43     flag[x][y]=true;
44  
45     d[x][y]=0;
46     for(i=0;i<4;i++)
47     {
48         tx=x+dir[i][0];
49         ty=y+dir[i][1];
50         if(map[tx][ty] && dis[x][y] == dis[tx][ty] + map[x][y])   //点睛之笔啊!!!
51             d[x][y]=(d[x][y]+dfs(tx,ty)) % M;
52     }
53     return d[x][y];
54 }
55 
56 
57 int main()
58 {
59 //    freopen("in.txt","r",stdin);
60     int i,j;
61     while(scanf("%d",&n)!=EOF)
62     {
63         if(n==0break;
64         memset(map,0,sizeof(map));
65         for(i=1; i<=n; ++i)
66             for(j=1; j<=n; ++j)
67             {
68                 scanf("%d",&map[i][j]);
69                 dis[i][j] = M+2;
70             }
71         for(i=1; i<n; ++i)
72             for(j=1; j<=n-i; ++j)
73             {
74                 map[i][j] += map[n-j+1][n-i+1];
75                 map[n-j+1][n-i+1] = 0;
76             }
77         bfs();
78         memset(flag,false,sizeof(flag));
79         int key=0;                   //计算相等路有多少条
80         for(i = 1; i <= n; i++)
81            if(mins == dis[i][n-i+1])
82                  key=(key+dfs(i,n-i+1)) % M;
83         printf("%d\n",key);
84 
85     }
86     return 0;
87 }

 本来想来个广度搜索,然后直接统计最短路径的个数,谁知悲剧啊,开始是MemoryL ,后来是TIMEL,最后参考了别人的代码觉得最后的dp用的很棒哦。。。

原文地址:https://www.cnblogs.com/yaling/p/3044947.html