题目:给定平面N*M的网格,每个里面有一个0-9的某个数字。求左上到右下的路径和最小,每次走相邻格。
分析:最短路。dijkstra+优先队列险过。尝试了各种算法,bellman-ford算法TLE,spfa+stack算法TLE。
注意:很卡常系数,o(╯□╰)o;采取一维状态记录TLE,利用二维状态记录可提高效率。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
int maze[1000][1000];
int value[1000][1000];
int visit[1000][1000];
int d[4][2] = {0,1,0,-1,1,0,-1,0};
//banery_heap
#define cmpdef <
int keys[1000000];
int base[1000000];
int In_h[1000000];
class banery_heap
{
private:
int size;
public:
banery_heap( int count = 1000000 ) {
size = 0;
memset( base, 0, sizeof( base ) );
memset( keys, 0, sizeof( keys ) );
memset( In_h, 0, sizeof( In_h ) );
}
bool empty(){return size == 0;}
void Insert( int ID, int Key ) {
if ( !In_h[ID] ) {
In_h[ID] = ++ size;
base[size] = ID;
}
keys[In_h[ID]] = Key;
int now = In_h[ID];
while ( now > 1 && keys[now] cmpdef keys[now>>1] ) {
swap( base[now], base[now>>1] );
swap( keys[now], keys[now>>1] );
swap( In_h[base[now]], In_h[base[now>>1]] );
now = now>>1;
}
}
int Delete( void ) {
swap( base[size], base[1] );
swap( keys[size], keys[1] );
swap( In_h[base[size]], In_h[base[1]] );
int now = 1;
while ( 1 ) {
int New = now,L = (now<<1),R = (now<<1)+1;
if ( L < size && keys[L] cmpdef keys[New] ) New = L;
if ( R < size && keys[R] cmpdef keys[New] ) New = R;
if ( now == New ) break;
swap( base[now], base[New] );
swap( keys[now], keys[New] );
swap( In_h[base[now]], In_h[base[New]] );
now = New;
}
return base[size --];
}
};
//end banery_heap
int dijkstra( int N, int M )
{
for ( int i = 0 ; i < N ; ++ i )
for ( int j = 0 ; j < M ; ++ j ) {
value[i][j] = 10000000;
visit[i][j] = 0;
}
banery_heap Heap;
Heap.Insert( 0, value[0][0] = maze[0][0] );
while ( !Heap.empty() ) {
int id = Heap.Delete();
visit[id/1000][id%1000] = 1;
for ( int i = 0 ; i < 4 ; ++ i ) {
int x = id/1000+d[i][0];
int y = id%1000+d[i][1];
if ( x >= 0 && x < N && y >= 0 && y < M && !visit[x][y] )
if ( value[x][y] > value[id/1000][id%1000] + maze[x][y] ) {
value[x][y] = value[id/1000][id%1000] + maze[x][y];
Heap.Insert( x*1000+y, value[x][y] );
}
}
}
return value[N-1][M-1];
}
int main()
{
int T,N,M;
while ( scanf("%d",&T) != EOF )
while ( T -- ) {
scanf("%d%d",&N,&M);
for ( int i = 0 ; i < N ; ++ i )
for ( int j = 0 ; j < M ; ++ j )
scanf("%d",&maze[i][j]);
printf("%d\n",dijkstra( N, M ));
}
return 0;
}