ACM-ICPC

From Usipedia
Jump to: navigation, search

Contents

ICPC Domestic 2010 Problem A: 角角画伯,かく悩みき

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1165&lang=jp

説明

入力と同時に下端・上端・左端・右端を更新していき,過去のタイル情報はtable[id]に入れるといいです.

Thanks: @mitsuchie

ソース

#include <iostream>
#include <cstring>
#include <set>
using namespace std;
 
typedef pair<int,int> pii;
 
#define N 400
pii table[N];
int l, r, t, bo;
int main(){
	int n;
	while(cin >> n && n){
		r = bo = N/2;
		l = t = N/2;
		table[0] = pii(N/2, N/2);
		for(int i=1; i<n; i++){
			int id, an;
			cin >> id >> an;
			int x = table[id].first;
			int y = table[id].second;
			if(an == 0){
				table[i] = pii(x-1, y);
				if(x-1 < l){
					l = x-1;
				}
			}
			if(an == 1){
				table[i] = pii(x, y-1);
				if(y-1 < t){
					t = y-1;
				}
			}
			if(an == 2){
				table[i] = pii(x+1, y);
				if(x+1 > r){
					r = x+1;
				}
			}
			if(an == 3){
				table[i] = pii(x, y+1);
				if(y+1 > bo){
					bo = y+1;
				}
			}
		}
		cout << r - l+1 << " " << bo - t +1 << endl;
	}
 
	return 0;
}

ICPC Domestic 2010 Problem B: 迷図と命ず

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1166&lang=jp

説明

壁情報を1つのマスに記録するために,迷路を縦横2倍に拡大します. 拡大すると経路の長さがおかしくなりますが,本来床だった場所にマークを付けておいて, そのマークを踏んだ時だけ移動距離をカウントするようにすると楽です. 迷路のテーブルを作り終わった後はBFSするだけです.

Thanks: @mitsuchie

ソース

#include <iostream>
#include <cstring>
#include <set>
using namespace std;
 
#define N 60
int w, h;
 
char table[N][N];
 
void view(){
	for(int y=0; y<2*h; y++){
		for(int x=0; x<2*w; x++){
			cout << table[y][x];
		}
		cout << endl;
	}
	cout << endl;
}
 
int main(){
	while(cin >> w >> h && (w|h)){
		memset(table, '*', N*N*sizeof(char));
		for(int y=0; y<h; y++){
			for(int x=0; x<w; x++){
				table[y*2][x*2] = '0';
			}
		}
		//view();
		for(int y=0; y<h; y++){
			// yoko kabe
			int in;
			for(int x=0; x<w-1; x++){
				cin >> in;
				//table[y][x] = '+';
				table[2*y+0][2*x+1] = in ? '*' : '+';
			}
			// tate kabe
			if(y == h-1){
				table[2*y+1][2*w-2] = '+';
			}else{
				for(int x=0; x<w; x++){
					cin >> in;
					table[2*y+1][2*x+0] = in ? '*' : '+';
				}
			}
		}
		//view();
 
		bool isCleared = false;
		typedef pair<int,pair<int,int> > pii;
		set<pii> s;
		s.insert(pii(1, make_pair(0, 0)));
		while(!s.empty()){
			int c = 0;
			int n = (*s.begin()).first;
			int x = (*s.begin()).second.first;
			int y = (*s.begin()).second.second;
			s.erase(s.begin());
 
			if(x<0 || y<0 || table[y][x]=='*') continue;
			if(x==2*w-2 && y==2*h-2){
				cout << n << endl;
				isCleared = true;
				break;
			}
 
			if(table[y][x] == '0'){
				c++;
			}
			table[y][x] = '*';
			s.insert(pii(n+c, make_pair(x+1, y)));
			s.insert(pii(n+c, make_pair(x-1, y)));
			s.insert(pii(n+c, make_pair(x, y+1)));
			s.insert(pii(n+c, make_pair(x, y-1)));
		}
		if(!isCleared)
			cout << 0 << endl;
	}
 
	return 0;
}

JAG Domestic 2009 Problem A: Luck Manipulator

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2149

説明

リール情報をキューに入れると良いです.

ソース

#include <iostream>
#include <queue>
using namespace std;
 
#define REP(i,n) for(int i=0;i<n;i++)
#define rep(n) REP(i,n)
#define MX 10000
int n, a, b, c;
 
int main(){
	int x;
	while(cin>>n>>a>>b>>c>>x && n){
		queue<int> q;
 
		rep(n){
			int in;
			cin >> in;
			q.push(in);
		}
 
		int i;
		for(i=0; i<=MX; i++){
			if(x == q.front()){
				q.pop();
			}
			if(q.empty()){
				break;
			}
			x = (a*x + b) % c;
		}
 
		if(i > MX){
			cout << -1 << endl;
		}else{
			cout << i << endl;
		}
	}
 
	return 0;
}

JAG Domestic 2009 Problem D: Restrictive Filesystem

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2152

説明

「何これ簡単じゃん!」かと思いきや,記憶媒体をint[10^9]などの配列で表すとメモリ容量は4Gbyte必要なのでどう頑張っても無理です. データ構造を工夫する必要があって,私はデータのセクタ番号(id)とその繰り返し回数(times)を持つDataクラスを作ってlistに入れて実装しました.

ソース

#include <iostream>
#include <list>
using namespace std;
 
#define REP(i,n) for(int i=0;i<n;i++)
#define rep(n) REP(i,n)
#define FOREACH_RANGE(it,s,e) for(typeof(s)it=s;it!=e;++it)
#define FOREACH(it,c) FOREACH_RANGE(it,(c).begin(),(c).end())
#define foreach(c) FOREACH(it,c)
#define foreach_range(s,e) FOREACH_RANGE(it,s,e)
 
#define MAX 1000000000
 
class Data {
public:
	int id, times;
	Data(int id, int times){
		this->id = id;
		this->times = times;
	}
	void put(){
		cout << id << " " << times << endl;
	}
};
int main(){
    int n;
    while(cin>>n&&n){
        list<Data> t;
        t.push_back(Data(-1, MAX+1));
 
        rep(n){
            string in;
            cin >> in;
            if(in == "W"){
                int out, c;
                int p = 0;
                cin >> out >> c;
				for(list<Data>::iterator it = t.begin(); ; it++){
					if((*it).id == -1){
						if(c >= (*it).times){
							(*it).id = out;
							c -= (*it).times;
						}else{
							int space = (*it).times;
							list<Data>::iterator next = it;
							advance(next, 1);
							t.erase(it);
							t.insert(next, Data(out, c));
							if(space-c > 0){
								t.insert(next, Data(-1, space-c));
							}
							it = next;
							c = 0;
						}
						if(c<=0) break;
					}
				}
            }else if(in == "D"){
                int a;
                cin >> a;
				foreach(t){
					if((*it).id == a){
						(*it).id = -1;
					}
				}
            }else if(in == "R"){
                int a;
                cin >> a;
				int pos = 0;
				foreach(t){
					pos += (*it).times;
					if(a < pos){
						cout << (*it).id << endl;
						break;
					}
 
				}
 
            }
        }
        cout << endl;
    }
 
    return 0;
}

JAG Domestic 2011 Problem A: koukyoukoukokukikou

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2252

説明

xor を使うと簡潔になります.

Thanks:@cq_71

ソース

#include <iostream>
#include <string>
using namespace std;
 
#define REP(i,p,n) for(int i=(int)p;i<(int)n;++i)
#define rep(i,n) REP(i,0,n)
 
bool isLeft(char c){
	if(c == 'q' || c == 'w' || c == 'e' || c == 'r' || c == 't' ||
		c == 'a' || c == 's' || c == 'd' || c == 'f' || c == 'g' || 
		c == 'z' || c == 'x' || c == 'c' || c == 'v' || c == 'b'){
		return true;
	}
	return false;
}
 
int main(){
	string in;
	while(cin >> in && in != "#"){
		int count = 0;
		rep(i, in.size()-1){
			count += isLeft(in[i]) ^ isLeft(in[i+1]);
		}
		cout << count << endl;
	}
 
	return 0;
}

JAG Domestic 2011 Problem B: Brave Force Story

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2253

説明

難易度の割に正答率が低くて意外に思うかもしれませんが, 「障害物の座標x, yの絶対値が30以下」という文章につられてフィールドを狭く取りがちです. 私は実際の答えよりも少ない数値が出力されるミスの原因になかなか気づけませんでした・・・

ソース

#include <iostream>
#include <algorithm>
#include <limits>
#include <queue>
#include <cstring>
using namespace std;
 
#define D(c) cout<<#c<<" = "<<c<<endl
#define REP(i,p,n) for(int i=(int)p;i<(int)n;++i)
#define rep(i,n) REP(i,0,n)
 
#define N 2000
char table[N][N];
 
 
class Point {
public:
	int x, y, t;
 
	Point(int x, int y, int t){
		this->x = x;
		this->y = y;
		this->t = t;
	}
};
 
queue<Point> q;
 
void tableInit(){
	memset(table, ' ', sizeof(table));
 
	// 番兵
	rep(x, N) {
		table[0][x] = '*';
		table[N-1][x] = '*';
	}
	rep(y, N) {
		table[y][0] = '*';
		table[y][N-1] = '*';
	}
 
	rep(i, N/2){
		table[i][N/2-1+i] = '*';
		table[N/2-1+i][i] = '*';
	}
}
 
void showTable(){
	rep(y, N){
		rep(x, N){
			printf("%c", table[y][x]);
		}
		printf("\n");
	}
	printf("\n");
}
 
char get(int x, int y){
	return table[y+N/2][x+N/2];
}
 
void set(int x, int y, char c){
	table[y+N/2][x+N/2] = c;
}
 
void fill(int x, int y, int t){
	if(get(x, y) == '*') return;
	set(x, y, '.');
	if(t == 0) return;
	fill(x+1, y, t-1);
	fill(x+1, y+1, t-1);
	fill(x, y+1, t-1);
	fill(x-1, y, t-1);
	fill(x-1, y-1, t-1);
	fill(x, y-1, t-1);
}
 
int count(){
	int count = 0;
	rep(y, N){
		rep(x, N){
			if(table[y][x] == '.') count++;
		}
	}
	return count;
}
 
void pushIfOk(int x, int y, int t){
	if(get(x, y) == '*' || get(x, y) == '.') return;
	q.push(Point(x, y, t));
	set(x, y, '.');
}
 
int main(){
	int t, n;
	while(cin >> t >> n){
		if(t == 0 && n == 0) break;
		tableInit();
 
		rep(blockCount, n){
			int x, y;
			cin >> x >> y;
			set(x, y, '*');
		}
		//showTable();
 
		int sx, sy;
		cin >> sx >> sy;
		pushIfOk(sx, sy, t);
 
		while(q.size() > 0){
			Point p = q.front();
			q.pop();
			if(p.t == 0) continue;
 
			pushIfOk(p.x+1, p.y, p.t-1);
			pushIfOk(p.x+1, p.y+1, p.t-1);
			pushIfOk(p.x, p.y+1, p.t-1);
			pushIfOk(p.x-1, p.y, p.t-1);
			pushIfOk(p.x-1, p.y-1, p.t-1);
			pushIfOk(p.x, p.y-1, p.t-1);
 
			//showTable();
		}
 
		//showTable();
		cout << count() << endl;
 
	}
 
	return 0;
}


JAG Domestic 2011 Problem C: 最短ルート

問題

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2254

説明

私は最初,愚直に全探査するなかなか計算が終わらないプログラムを書いてしました. ビットDPを使うべきです(詳しくはアリ本や http://www.slideshare.net/iwiwi/ss-3578511 に載っています).

ソース

#include <iostream>
#include <algorithm>
#include <limits>
#include <cstring>
using namespace std;
 
#define D(c) cout<<#c<<" = "<<c<<endl
#define REP(i,p,n) for(int i=(int)p;i<(int)n;++i)
#define rep(i,n) REP(i,0,n)
#define MAX_N 16
#define INF 1100000000
 
int n;
int d[MAX_N][MAX_N+1];
int dp[1 << MAX_N][MAX_N];
 
int searchMin(int S, int v){
	// 入手可能な装備で一番コストが低いものを探して返す
	if(S == 0 && v == 0) return 0;
	int min = d[v][0];
	rep(i, n){
		if(i == v){
			continue;
		}
		if((S >> i) & 1){
			int cost = d[v][i+1];
			if(cost < min){
				min = cost;
			}
		}
	}
	return min;
}
 
// 既に訪れた点がS, 現在位置がv
// Sの下位からnビット目が1なら,既にステージn+1に訪れた事を意味する
int rec(int S, int v){
	if(dp[S][v] >= 0){
		return dp[S][v];
	}
 
	int nowCost = searchMin(S, v);
 
	// すべての頂点を訪れ終えた
	if(S == (1 << n) - 1){
		return dp[S][v] = nowCost;
	}
 
	int res = INF;
	rep(u, n){
		if(!(S >> u & 1)){
			// 次のuに移動 & 最小コストを更新
			res = min(res, rec(S | 1 << u, u) + nowCost);
		}
	}
	return dp[S][v] = res;
}
 
int main(){
	while(cin>>n&&n){
		memset(dp, -1, sizeof(dp));
		int in;
		rep(y, n){
			rep(x, n+1){
				cin >> in;
				d[y][x] = in;
			}
		}
 
		cout << rec(0, 0) << endl;
	}
 
	return 0;
}
Namespaces
Variants
Views
Actions
Categories