1 /**************************************************************
2 Problem: 1001
3 User: 935671154
4 Language: C++
5 Result: Accepted
6 Time:8536 ms
7 Memory:104700 kb
8 ****************************************************************/
9
10 #include <iostream>
11 #include <cctype>
12 #include <cstdio>
13 #include <vector>
14 #include <algorithm>
15 #include <cmath>
16 #include <queue>
17 using namespace std;
18 inline void getd(int &x){
19 char c = getchar();
20 bool minus = 0;
21 while(!isdigit(c) && c != ‘-‘)c = getchar();
22 if(c == ‘-‘)minus = 1, c = getchar();
23 x = c - ‘0‘;
24 while(isdigit(c = getchar()))x = x * 10 + c - ‘0‘;
25 if(minus)x = -x;
26 }
27 /*======================================================*/
28 const int maxn = 2000003, INF = 0x3f3f3f3f;
29 #define pb push_back
30 struct edge{
31 int to, w;
32 edge(int t, int W):to(t), w(W){}
33 };
34 vector<edge> adj[maxn];
35 int N, M, To, dis[maxn] = {0};
36
37 inline bool init(){
38 int i, j, k, t, d;
39 getd(N), getd(M);
40 if(N == 1){
41 int ans = INF;
42 for(i = 1;i < M;++i)
43 getd(t), ans = min(ans, t);
44 printf("%d\n", ans);
45 return 0;
46 }
47 if(M == 1){
48 int ans = INF;
49 for(i = 1;i < N;++i)
50 getd(t), ans = min(ans, t);
51 printf("%d\n", ans);
52 return 0;
53 }
54 To = ((N-1) * (M-1) * 2) + 1;
55 //横向道路
56 d = 2 * M - 3;
57 for(i = k = 1;i < M;++i, k+=2){
58 getd(t);
59 adj[0].pb(edge(k, t));
60 }
61 for(i = 2;i < N;++i){
62 for(j = 1;j < M;++j, k+=2){
63 getd(t);
64 adj[k].pb(edge(k-d, t));
65 adj[k-d].pb(edge(k, t));
66 }
67 }
68 for(j = 1, k = To-2*(M-2)-1;j < M;++j, k+=2){
69 getd(t);
70 adj[k].pb(edge(To, t));
71 }
72 //纵向道路
73 for(i = 1,k = 2;i < N;++i){
74 getd(t);
75 adj[k].pb(edge(To, t));
76 for(j = 2,k+=2;j < M;++j,k+=2){
77 getd(t);
78 adj[k].pb(edge(k-3, t));
79 adj[k-3].pb(edge(k, t));
80 }
81 getd(t);
82 adj[0].pb(edge(k-3, t));
83 }
84 //斜向道路
85 for(i = 1, k = 1;i < N;++i){
86 for(j = 1;j < M;++j, k += 2){
87 getd(t);
88 adj[k].pb(edge(k+1, t));
89 adj[k+1].pb(edge(k, t));
90 }
91 }
92 for(i = 1;i <= To;++i)
93 dis[i] = INF;
94 return 1;
95 }
96 queue<int> Q;
97 bool inQ[maxn] = {1};
98 inline void work(){
99 Q.push(0);
100 int t;
101 vector<edge>::iterator it;
102 while(!Q.empty()){
103 t = Q.front();Q.pop();inQ[t] = 0;
104 for(it = adj[t].begin();it != adj[t].end();++it)
105 if(dis[t] + it->w < dis[it->to]){
106 dis[it->to] = dis[t] + it->w;
107 if(!inQ[it->to])
108 Q.push(it->to), inQ[it->to] = 1;
109 }
110 }
111 printf("%d\n", dis[To]);
112 }
113
114 int main(){
115 #if defined DEBUG
116 freopen("test", "r", stdin);
117 #endif
118
119 if(init())
120 work();
121
122 #if defined DEBUG
123 cout << endl << (double)clock()/CLOCKS_PER_SEC << endl;
124 #endif
125 return 0;
126 }