『ACM/ICPC国内予選突破の手引き』をやってみる(5)

ACM/ICPC国内予選突破の手引き”Step by step”の難易度:☆☆☆ スタート。

Problem 2008 : Dragon Fantasy

  • 難易度 : ☆☆☆
  • 種類 : 探索

解説見てやっとできた。
(double)<=(double)という比較をしたいとき、doubleの計算では誤差があるため==の比較ができない。
したがって、==の場合に対応するために

if( dist( c[i].x-d.x, c[i].y-d.y ) < new_t + 1e-10 )

みたいに、近似値を使用する。これは大事らしいので覚える。

#include <iostream>
#include <deque>
#include <cmath>

using namespace std;

struct POINT {
	int x, y;
	bool v;
} c[21], p, d;
int n;
bool Ans;


inline double dist( int dx, int dy ){
	return sqrt( (double)dx*dx + (double)dy*dy );
}

void solve( double t, int x, int y )
{
	if( Ans ) return;

	int i, cnt;
	double new_t;

	cnt = 0;
	for( i=0; i<n; i++ ){
		if( c[i].v ){
			cnt++;
			continue;
		}

		new_t = t + dist( c[i].x-x, c[i].y-y );
		if( dist( c[i].x-d.x, c[i].y-d.y ) < new_t + 1e-10 )
			return;
	}

	if( cnt == n ){
		Ans = true;
		return;
	}

	for( i=0; i<n; i++ ){
		if( Ans ) break;
		if( c[i].v ) continue;

		new_t = t + dist( c[i].x-x, c[i].y-y );
		c[i].v = true;
		solve( new_t, c[i].x, c[i].y );
		c[i].v = false;
	}

	return;
}

int main(void)
{
	while( cin >> n >> p.x >> p.y >> d.x >> d.y ){
		if( n == 0 && p.x == 0 && p.y == 0 && d.x == 0 && d.y == 0 )
			break;

		for( int i=0; i<n; i++ ){
			cin >> c[i].x >> c[i].y;
			c[i].v = false;
		}
		Ans = false;

		solve( 0, p.x, p.y );
		if( Ans )
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}

	return 0;
}

Problem 1126 : The Secret Number

  • 難易度 : ☆☆☆
  • 種類 : DP

DPだと考えるとなかなか簡単だった。
でも気づくのが難しい…。

#include <iostream>
#include <deque>
#include <string>

using namespace std;

#define MAX 70


string mat[MAX+2][MAX+2];
int w, h;

string maxString( string a, string b )
{
	if( a.size() > b.size() )
		return a;
	if( a.size() < b.size() )
		return b;

	for( int i=0; i<a.size(); i++ ){
		if( a[i] > b[i] )
			return a;
		if( a[i] < b[i] )
			return b;
	}

	return a;
}

int main(void)
{
	int i, j;
	string input, max, tmp[2];

	for( i=0; i<=h+1; i++ )
		for( j=0; j<=w+1; j++ )
			mat[i][j] = "";

	while( cin >> w >> h, w != 0 && h != 0 ){
		max = "";

		for( i=1; i<=h; i++){
			cin >> input;
			for( j=1; j<=w; j++ )
				mat[i][j] = input[j-1];
		}

		for( i=1; i<=h; i++ ){
			for( j=1; j<=w; j++ ){
				if( "A" <= mat[i][j] && mat[i][j] <= "Z" )
					continue;
				
				tmp[0] = tmp[1] = "";
				if( '0' < mat[i-1][j][0] && mat[i-1][j][0] <= '9' )
					tmp[0] = maxString( mat[i][j], mat[i-1][j]+mat[i][j] );
				if( '0' < mat[i][j-1][0] && mat[i][j-1][0] <= '9' )
					tmp[1] = maxString( mat[i][j], mat[i][j-1]+mat[i][j] );
				mat[i][j] = maxString( maxString( mat[i][j], tmp[0] ), tmp[1] );
				max = maxString( max, mat[i][j] );
			}
		}

		cout << max << endl;
	}

	return 0;
}

Problem 2011 : Gather the Maps!

  • 難易度 : ☆☆☆
  • 種類 : DP

まえーに一回解いたことがあったので、解説ナシで解けた。

#include <iostream>
#include <vector>

using namespace std;


int n;
int d[51][31];	// d[子孫の番号][日付] = 1:出席できる / 2:できない
int p[51][51];	// p[子孫の番号][地図の断片の番号] = 1:所持 / 2:所持していない

// すべての地図の断片を持っている人が存在すればtrueを返す。
bool check()
{
	int i, j;

	for( i=1; i<=n; i++ ){
		for( j=1; j<=n; j++ )
			if( !p[i][j] )
				break;

		if( j == n+1 )
			return true;
	}

	return false;
}

// 初期化
void initialize()
{
	int i, j;

	for( i=0; i<=n; i++ ){
		for( j=0; j<=30; j++ )
			d[i][j] = 0;

		for( j=0; j<=n; j++ ){
			if( i == j )
				p[i][j] = 1;
			else
				p[i][j] = 0;
		}
	}

	return;
}

int main(void)
{
	int f, i, j, k, input;
	vector<int> list;

	while( cin >> n, n != 0 ){

		initialize();

		// 入力
		for( i=1; i<=n; i++ ){
			cin >> f;
			for( j=0; j<f; j++ ){
				cin >> input;
				d[i][input] = 1;
			}
		}

		// 日ごと
		for( i=0; i<=30; i++ ){
			// 出席できる人を探す
			list.clear();
			for( j=1; j<=n; j++ )
				if( d[j][i] )
					list.push_back(j);
			if( list.size() == 0 )
				continue;

			// 地図の交換
			int work = 0;
			for( j=1; j<=n; j++ ){
				work = 0;
				for( k=0; k<list.size(); k++ )
					work += p[list[k]][j];
				work = ( work ) ? 1 : 0;
				for( k=0; k<list.size(); k++ )
					p[list[k]][j] = work;
			}

			if( check() )
				break;
		}

		// 結果の出力
		if( i <= 30 )
			cout << i << endl;
		else
			cout << "-1" << endl;

	}

	return 0;
}