質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

1回答

1445閲覧

蟻本p153 座標圧縮の関数がうまく機能しない

rdld036

総合スコア16

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

0クリップ

投稿2021/09/26 22:40

前提・実現したいこと

以下の問題を解いているのですが、次の座標圧縮の関数を用いても領域が圧縮されません。具体的にどこが誤っているのかご指摘いただけると幸いです。よろしくお願いします。

問題
W * Hの格子状にN本の垂直または水平な幅1の直線が引かれています。格子は線によって何個の領域に分かれているか。
入力サンプル
W = 10, H = 10, N = 5
X1 = {1, 1, 4, 9, 10}
X2 = {6, 10, 4, 9, 10}
Y1 = {4, 8, 1, 1, 6}
Y2 = {4, 8 10, 5, 10}

X1[i], X2[i], Y1[i], Y2[i]はi番目の直線の2つの端点の座標((X1[i], Y1[i]), (X2[i], Y2[i]))

該当のソースコード

c++

1#include <bits/stdc++.h> 2using namespace std; 3typedef long long ll; 4typedef long double ld; 5 6const int INF = 1e9; 7 8template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; } 9template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; } 10template <typename Type> inline string toString(const Type &a){ostringstream oss; oss << a; return oss.str();} 11 12int W, H, N; 13 14 15int compress(vector<int> &x1, vector<int> &x2, int w){ 16 vector<int> xs; 17 for(int i = 0; i < N; ++i){ 18 for(int d= -1; d <= 1; ++d){ 19 int tx1 = x1[i] + d, tx2 = x2[i] + d; 20 if(tx1 >= 1 && tx1 <= w){ 21 xs.push_back(tx1); 22 } 23 if(tx2 >= 1 && tx2 <= w){ 24 xs.push_back(tx2); 25 } 26 } 27 } 28 sort(xs.begin(), xs.end()); 29 auto it = unique(xs.begin(), xs.end()); 30 xs.erase(it, xs.end()); 31 for(int i = 0; i < N; ++i){ 32 x1[i] = lower_bound(xs.begin(), xs.end(), x1[i]) - xs.begin(); 33 x2[i] = lower_bound(xs.begin(), xs.end(), x2[i]) - xs.begin(); 34 } 35 return xs.size(); 36} 37 38vector<vector<int>> tile; 39vector<int> X1, X2, Y1, Y2; 40int dx[4] = {1, 0 , -1, 0}, dy[4] = {0, 1, 0, -1}; 41int main(){ 42 ios::sync_with_stdio(false); 43 cin.tie(0); 44 cin >> W >> H >> N; 45 X1.resize(N); 46 X2.resize(N); 47 Y1.resize(N); 48 Y2.resize(N); 49 for(int i = 0; i < N; ++i) cin >> X1[i]; 50 for(int i = 0; i < N; ++i) cin >> X2[i]; 51 for(int i = 0; i < N; ++i) cin >> Y1[i]; 52 for(int i = 0; i < N; ++i) cin >> Y2[i]; 53 W = compress(X1, X2, W); H = compress(Y1, Y2, H); 54 tile.assign(H, vector<int>(W, 0)); 55 for(int i = 0; i < N; ++i){ 56 for(int y = Y1[i]; y <= Y2[i]; ++y){ 57 for(int x = X1[i]; x <= X2[i]; ++x){ 58 tile[y][x] = 1; 59 } 60 } 61 } 62 63 int ans = 0; 64 for(int y = 0; y < H; ++y){ 65 for(int x = 0; x < W; ++x){ 66 if(tile[y][x]) continue; 67 queue<pair<int, int>> que; 68 que.push(make_pair(x, y)); 69 tile[y][x] = 1; 70 ans++; 71 while(!que.empty()){ 72 pair<int, int> p = que.front(); que.pop(); 73 for(int i = 0; i < 4; ++i){ 74 int nx = p.first + dx[i], ny = p.second = p.second + dy[i]; 75 if(nx >= 0 && nx < W && ny >= 0 && ny < H){ 76 if(tile[ny][nx]) continue; 77 else{ 78 que.push(make_pair(nx,ny)); 79 tile[ny][nx] = 1; 80 } 81 } 82 } 83 } 84 85 } 86 } 87 cout << ans << endl; 88 89}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yudedako67

2021/09/27 02:24

うまくいっていないと考えているのはなぜですか? 例えば「~という結果になるはずだが、~という結果になる」
rdld036

2021/09/27 02:55

恐らく問題があるのは全探索の方でしょうか。今回のサンプルだと、蟻本では答えが6になるのにこのコードでやると、forループで座標(4,0)を起点に幅全探索をした時座標(4,4,)が探索されず残り、その分一つ余計に領域をカウントすることにより7になります。ただ、なぜこの点だけ飛ばされるのか教えていただけますか
guest

回答1

0

ベストアンサー

int nx = p.first + dx[i], ny = p.second = p.second + dy[i];

Why do you change p.second ?

投稿2021/09/27 04:30

fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/09/27 04:38

You wrote the code, and the result was wrong. If so, you need to debug. Why don't ?
rdld036

2021/09/27 04:41

That's a typo...Thank you for letting me know!
rdld036

2021/09/27 04:47

I debugged it but it didn't display any error messages
fana

2021/09/27 04:53

ああ,もう,めんどくさいから日本語で書くけどもさ, 結果値がおかしい ってときにエラーメッセージなんか出るわけないのよね. 探索処理がおかしいと思うなら,探索している座標のチェックくらいするっしょ,ふつーは. 想定した探索順はご自身で知っているんだから,それと実際の探索座標の順序を見比べるとかすれば こんな単純ミスを見つけるのには5分もいらないハズ. 何か動きがおかしい,っていうなら,「ちゃんと想定通りに動いてるんか?」っていうのを見る. 何を見れば何を確認できるのか? っていう視点に立って,見るべきものを見る.
fana

2021/09/27 05:02

> 座標(4,4) が1にならん,っていう異常をせっかく発見したんだから, 「何でそうなるのか?」という要因も考えようよ. 1にする処理は queue に突っ込む処理と同じ個所にあるんだから, 原因は「queueに突っ込むべき座標が異常になってるのでは?」というところまでは推測できる. ↓ そしたら,「座標をqueueに突っ込む処理」のあたりで実際には何が起こってるのか? を見る. 事件の様子から 推理して,証拠を集めて,犯人を突き止める. 事件を見つけるだけじゃダメだ.
fana

2021/09/27 05:08 編集

あと,全然関係ないけども,今回のコードは int nx = p.first + dx[i]; int ny = p.second = p.second + dy[i]; って2行で書いてれば,見た目から瞬間的に間違いに気づけるものだったと思う. (一方だけが異常に長い)
rdld036

2021/09/27 05:12

書式についてもこれから気をつけたいと思います。大切なことを色々教えてくださり誠にありがとうございます。
fana

2021/09/27 05:18

わざわざこの手のパズルみたいな問題に取り組んでるのは 考えることを楽しんでるんだろう,と思うので, デバッグも同じように楽しめばいいんじゃないかな. そしたら一粒で二度おいしい.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問