ラベル aoj の投稿を表示しています。 すべての投稿を表示
ラベル aoj の投稿を表示しています。 すべての投稿を表示

2012年1月3日火曜日

2014: Surrounding Area



今日も簡単そうな問題から。


2014: Surrounding Area


以下クソース。


実装簡単だと思ってたら結構手こずった。コーディング力うんこ…。



#include <stdio.h>

#define MAX_WH 50
#define BLACK 1
#define WHITE 2

char map[MAX_WH][MAX_WH + 1];
char flag[MAX_WH][MAX_WH + 1];

int w, h;

void printFlag() {
int i, j;
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) printf("%d", flag[j][i]);
puts("");
}
puts("****************");
}

int count(int n) {
int i, j, cnt = 0;
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
if (flag[j][i] == n) cnt++;
}
}
return cnt;
}

void reset_flag() {
int i, j;
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
flag[j][i] = 0;
}
}
}

int rinsetsu(int mask, int x, int y) {
char c = mask == BLACK ? 'B' : 'W';
if (0 <= x + 1 && x + 1 < w && map[y][x + 1] == c) return 1;
if (0 <= x - 1 && x - 1 < w && map[y][x - 1] == c) return 1;
if (0 <= y + 1 && y + 1 < h && map[y + 1][x] == c) return 1;
if (0 <= y - 1 && y - 1 < h && map[y - 1][x] == c) return 1;
return 0;
}

int kakudai_rinsetsu(int mask, int x, int y) {
if (0 <= x + 1 && x + 1 < w && flag[y][x + 1] & mask) return 1;
if (0 <= x - 1 && x - 1 < w && flag[y][x - 1] & mask) return 1;
if (0 <= y + 1 && y + 1 < h && flag[y + 1][x] & mask) return 1;
if (0 <= y - 1 && y - 1 < h && flag[y - 1][x] & mask) return 1;
return 0;
}

void fill(int mask, int x, int y) {
if (0 <= x && x < w && 0 <= y && y < h) {
int c = map[y][x];
if (c == 'B' || c == 'W') return;
if (flag[y][x] & mask) return;

if (rinsetsu(mask, x, y) || kakudai_rinsetsu(mask, x, y)) {
flag[y][x] |= mask;
fill(mask, x + 1, y);
fill(mask, x, y + 1);
fill(mask, x - 1, y);
fill(mask, x, y - 1);
}
}
}

void solve() {
int i, j;

for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
if (map[j][i] == 'B' || map[j][i] == 'W') {
int mask = map[j][i] == 'B' ? BLACK : WHITE;
fill(mask, i + 1, j);
fill(mask, i, j + 1);
fill(mask, i - 1, j);
fill(mask, i, j - 1);
}
}
}

printf("%d %d\n", count(BLACK), count(WHITE));
}

int main() {
int i;
while (1) {
scanf("%d %d\n", &w, &h);
if (!(w | h)) break;

for (i = 0; i < h; i++) {
scanf("%s\n", map[i]);
}
reset_flag();

solve();
}
return 0;
}





2012年1月2日月曜日

久々にAOJをやった。



今日やったことまとめ。


久々にAizu Online Judgeをやった。


Problem setのVolume 0で解いてないやつを。


最後にやったのは2011-05-01なので、おおよそ8ヶ月ぶり。


くソースアップしときます。


0068: Enclose Pins with a Rubber Band


解法分かんなくてググて出たページで凸包というのを初めて知るなど…。


その単語だけ見てアルゴリズム書いてるページへ。


点集合の凸包-数学アルゴリズム演習ノート-


deq notesさんのベクトルのページ等を見てなんとか解けた。


超時間かかった。



#include <cstdio>
#include <complex>

using namespace std;

#define MAX_N 100

typedef complex<double> P;
#define EPS (1e-10)
#define EQ(a,b) (abs((a) - (b)) < EPS)
#define EQV(a,b) (EQ((a).real(), (b).real()) && EQ((a).imag(), (b).imag()))

double cross(P a, P b) {
return (a.real() * b.imag() - a.imag() * b.real());
}

int side(P start, P end, P point) {
double arg = cross(end - start, point - start);
if (arg > 0) return 1; // left
if (arg < 0) return -1; // right
return 0; // center
}

int n;
P p[MAX_N];

int next_vertex(int start_index) {
for (int i = 0; i < n; ++i) {
if (start_index == i) continue;
bool right = false;
for (int j = 0; j < n; ++j) {
if (i == j) continue;
if (side(p[start_index], p[i], p[j]) == -1) right = true;
}
if (!right) return i;
}
return start_index;
}

int main() {
while (1) {
scanf("%d\n", &n);
if (!n) break;

for (int i = 0; i < n; ++i) {
double x, y;
scanf("%lf,%lf\n", &x, &y);
p[i] = P(x, y);
}

int pm = 0;
for (int i = 0; i < n; ++i) {
if (p[pm].real() > p[i].real()) pm = i;
}

int start = pm;
int current = next_vertex(start);
int count = 1;

while (start != current) {
current = next_vertex(current);
count++;
}
printf("%d\n", n - count);
}
return 0;
}


0069 Drawing Lots II


左右の横線の有無を確認するのを忘れてWAいっぱい出しちゃった。



#include <stdio.h>

int n, m, hit, d;
char dan[30][11];

int amida() {
int i;
int cur = m;
for (i = 0; i < d; ++i) {
// right
if (cur < n && dan[i][cur - 1] == '1') {
cur = cur + 1;
}
// left
else if (cur > 1 && dan[i][cur - 2] == '1') {
cur = cur - 1;
}
}
return cur == hit;
}


void solve() {
int i, j;
if (amida()) {
puts("0");
return;
}

for (i = 0; i < d; i++) {
for (j = 0; j < n - 1; j++) {
if (dan[i][j] == '0') {
if (j > 0 && dan[i][j-1] == '1') continue;
if (j < n - 2 && dan[i][j+1] == '1') continue;
dan[i][j] = '1';
if (amida()) {
printf("%d %d\n", i+1, j+1);
return;
}
dan[i][j] = '0';
}
}
}

puts("1");
}

int main() {
int i;
while (1) {
scanf("%d\n", &n);
if (!n) break;

scanf("%d\n%d\n%d\n", &m, &hit, &d);
for (i = 0; i < d; i++) {
scanf("%s\n", dan[i]);
}
solve();
}
return 0;
}


0078: Magic Square


魔方陣の問題。


return 0を忘れてRE



マス目に入る各数字は右詰4桁で出力してください。


を見落としPresentation errorでした。



#include <stdio.h>

#define MAX_N 15

int sq[MAX_N][MAX_N];
int n;

void reset() {
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
sq[i][j] = -1;
}
}
}

void fill(int count, int x, int y) {
if (count > n * n) return;
if (x < 0) x = n - 1;
if (x >= n) x = 0;
if (y >= n) y = 0;
if (sq[x][y] != -1) {
fill(count, x - 1, y + 1);
} else {
sq[x][y] = count;
fill(count + 1, x + 1, y + 1);
}
}

void printSq() {
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
printf(j ? "%4d" : "%4d", sq[j][i]);
}
puts("");
}
}

void solve() {
int center = n / 2;
reset();
sq[center][center + 1] = 1;
fill(2, center + 1, center + 2);
printSq();
}

int main() {
while (1) {
scanf("%d\n", &n);
if (!n) break;

solve();
}
return 0;
}


まとめ


やっぱり数学的な知識がないと辛いかも。


皆どうやって覚えてるんだろう。


あと解法分かんないときどしたらいい? 解法ググってでも解いたらいい?


僕頭固いからかなー。


とりえあずこんな感じで毎日解いていけるといいな。


次やるときは問題文をしっかり読んで重要なとこ見落とさないようにする。


目指せ一発Accept!