Volume 5 / 0515
情報オリンピック 2006予選 解答
Problem 0515 : School Road / 通学経路
高1で習った数学Aにあるような、碁盤目状に繋がっている点間の最短経路の数を求める問題。
深さ優先で解くと時間切れでアウト。
(x,y)までの最短経路の数 = (x-1,y)までの最短経路 + (x,y-1)までの最短経路
が成り立つので幅優先(……だよね?)で解く。
#include <iostream> #include <vector> #include <queue> using namespace std; void solve( vector< vector<int> > node, int w, int h ) { int x, y; queue<int> pos_x, pos_y; vector< vector<int> > v = node; node[1][1] = 1; v[1][1] = -1; pos_x.push(2); pos_y.push(1); pos_x.push(1); pos_y.push(2); while( pos_x.size() > 0 && pos_y.size() > 0 ){ x = pos_x.front(); y = pos_y.front(); pos_x.pop(); pos_y.pop(); if( v[y][x] != -1 ){ node[y][x] = 0; if( node[y-1][x] != -1 ) node[y][x] += node[y-1][x]; if( node[y][x-1] != -1 ) node[y][x] += node[y][x-1]; v[y][x] = -1; if( x+1 <= w ){ pos_x.push(x+1); pos_y.push(y); } if( y+1 <= h ){ pos_x.push(x); pos_y.push(y+1); } } } cout << node[h][w] << endl; return; } int main(void) { int w, h, x, y, n, i; vector< vector<int> > node; while( cin >> w >> h, w!=0 && h!= 0 ){ node.clear(); node.resize( h+2 ); for( y=0; y<node.size(); y++ ) node[y].resize( w+2, 0 ); cin >> n; for( i=0; i<n; i++ ){ cin >> x >> y; node[y][x] = -1; } solve( node, w, h ); } return 0; }
ちなみに、深さ優先でやったのが次。
// 時間切れでアウト int solve( vector< vector<bool> > node, int x0, int y0 ) { if( x0 == node[0].size()-2 && y0 == node.size()-2 ) return 1; int cnt = 0; if( node[y0][x0+1] && x0+1 < node[0].size()-1 ) cnt += solve( node, x0+1, y0 ); if( node[y0+1][x0] && y0+1 < node.size()-1 ) cnt += solve( node, x0, y0+1 ); return cnt; } int main(void) { int w, h, x, y, n, i; vector< vector<bool> > node; while( cin >> w >> h, w!=0 && h!= 0 ){ node.clea(); node.resize( h+2 ); for( y=0; y<node.size(); y++ ) node[y].resize( w+2, true ); cin >> n; for( i=0; i<n; i++ ){ cin >> x >> y; node[y][x] = false; } cout << solve( node, 1, 1 ) << endl; } return 0; }