会津オンラインジャッジ:Finding Missing Cards

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

会津オンラインジャッジ:Finding Missing Cards

#1

投稿記事 by みけCAT » 9年前

http://rose.u-aizu.ac.jp/onlinejudge/Pr ... 15&lang=jp
の問題で、以下のソースコードを書いたのですが、Runtime Errorと出ました。
printfでデバッグしたところ、カードの種類を入力した段階でfor文を一回回ってしまうようです。
いい書き方があったら教えてください。
お願いします。

コード:

#include <stdio.h>

int main(void) {
	int sonzai[52];
	int n;
	int i;
	char kindc[4]={'S','H','C','D'};
	char kind;
	int num;
	for(i=0;i<52;i++)sonzai[i]=0;
	scanf("%d",&n);
	for(i=0;i<n;i++) {
		scanf("%c %d",&kind,&num);
		switch(kind) {
			case 'D':num+=13;
			case 'C':num+=13;
			case 'H':num+=13;
			case 'S':num+=13;
		}
		sonzai[num-1]=1;
	}
	for(i=0;i<52;i++) {
		if(sonzai[i]==0)
			printf("%c %d\n",kindc[i/13],i%13+1);
	}
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
五反田
記事: 21
登録日時: 9年前
住所: 千葉

Re: 会津オンラインジャッジ:Finding Missing Cards

#2

投稿記事 by 五反田 » 9年前

カードの種類を読み取る際に、バッファに残っている改行を読み込んでしまっているようです。
そこで以下のように%cの前(と一応%dの後にも)スペースを入れて、空白を読み飛ばすようにし、さらにcaseの最後の+=13はいらないので、コメントアウトしたら無事Acceptされましたよ。

コード:

#include <stdio.h>
 
int main(void) {
    int sonzai[52];
    int n;
    int i;
    char kindc[4]={'S','H','C','D'};
    char kind;
    int num;
    for(i=0;i<52;i++)sonzai[i]=0;
    scanf("%d",&n);
    for(i=0;i<n;i++) {
        scanf(" %c %d ",&kind,&num);
        switch(kind) {
            case 'D':num+=13;
            case 'C':num+=13;
            case 'H':num+=13;
            //case 'S':num+=13;
        }
        sonzai[num-1]=1;
    }
    for(i=0;i<52;i++) {
        if(sonzai[i]==0)
            printf("%c %d\n",kindc[i/13],i%13+1);
    }
    return 0;
}

アバター
bitter_fox
記事: 607
登録日時: 9年前
住所: 大阪府

Re: 会津オンラインジャッジ:Finding Missing Cards

#3

投稿記事 by bitter_fox » 9年前

すべてのscanf文に対して

コード:

scanf("%d",&n);
while (getchar() != '\n');
while (getchar() != '\n'); をはさんでみてください。scanfは最後の改行もバッファとして残して処理を終了するので、getcharで改行まで読み込んでやる必要があります。

switch文でbreakが無いのは、仕様ですよね??

七篠

Re: 会津オンラインジャッジ:Finding Missing Cards

#4

投稿記事 by 七篠 » 9年前

横槍で質問に質問を返すので大変申し訳ないのですが、

この問題はNoteに
int cards[4][13]; // bool でもよい
と書いてあり、おそらく2次元配列の勉強をしろということだと思うのですが、わざわざ単なる配列で考えるのでしょうか。
二次元配列ですればわかりやすいというのを使わないのはもったいないです。


考え方は
最初の文字で繰り返す回数をきめて、その後に入力するトランプの種類に合わせたところにフラグを立てて(最初に繰り返す回数分)、([4]*[13]回分 )最後にフラグがたたなかったところ(=存在しないもの)だけ出力すればいいと思います。

[4]*[13]回分 の繰り返し方法は
for(4回文の繰り返し文){
 for(13回文の繰り返し文){
  判定と出力処理
 }

という感じだと思います。 二次元配列は覚えるととても便利ですのでがんばってください

アバター
ゆーずぃ
記事: 62
登録日時: 9年前
住所: 埼玉県

Re: 会津オンラインジャッジ:Finding Missing Cards

#5

投稿記事 by ゆーずぃ » 9年前

bitter_fox さんが書きました:すべてのscanf文に対して

コード:

scanf("%d",&n);
while (getchar() != '\n');
while (getchar() != '\n'); をはさんでみてください。scanfは最後の改行もバッファとして残して処理を終了するので、getcharで改行まで読み込んでやる必要があります。
このトピック自体とは関係ありませんが、他の方が後で閲覧する時の為に念の為。
scanfで最後の改行をバッファに残してしまうのは代入抑止(%*c)で防げます。(期待通りの入力が行われた場合のみ。)
ちなみに既にストリームに入っている改行は、%c以外の場合デフォルトで無視されます。
%cの場合でも、今回の問題のように確実に期待された入力がされる(エラー判定処理の必要が無い)のであれば、

char c;
char s[10];
scanf("%c",&c);
scanf("%s%*c",s); 

又、逆ならば
scanf("%s",s);
scanf(" %c%*c",&c);
で充分です。

有名な、空白を入れる
scanf(" %c",&c);
は、既にストリームに改行・空白・タブが入っている場合に読み飛ばすだけなので気を付けて下さい。(自身の改行を打ち消すものではありません。)

知っておいて損は無いと思います。横から失礼しましたm(_ _)m

//本文修正しました

アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: 会津オンラインジャッジ:Finding Missing Cards

#6

投稿記事 by みけCAT » 9年前

bitter_foxさん
この方法で解決しました。ありがとうございます。
switch文でbreakが無いのは、仕様ですよね??
仕様です。

コード:

#include <stdio.h>

int main(void) {
	int sonzai[52];
	int n;
	int i;
	char kindc[4]={'S','H','C','D'};
	char kind;
	int num;
	for(i=0;i<52;i++)sonzai[i]=0;
	scanf("%d",&n);
	while (getchar()!='\n');
	for(i=0;i<n;i++) {
		scanf("%c %d",&kind,&num);
		while (getchar()!='\n');
		switch(kind) {
			case 'D':num+=13;
			case 'C':num+=13;
			case 'H':num+=13;
			/*case 'S':num+=13;*/
		}
		sonzai[num-1]=1;
	}
	for(i=0;i<52;i++) {
		if(sonzai[i]==0)
			printf("%c %d\n",kindc[i/13],i%13+1);
	}
	return 0;
}
七篠さん
二次元配列のコードでもAcceptされました。ありがとうございます。

コード:

#include <stdio.h>

int main(void) {
	int sonzai[4][13];
	int n;
	int i;
	int c;
	char kindc[4]={'S','H','C','D'};
	char kind;
	int num;
	for(c=0;c<4;c++) {
		for(i=0;i<13;i++)sonzai[c][i]=0;
	}
	scanf("%d",&n);
	while (getchar()!='\n');
	for(i=0;i<n;i++) {
		scanf("%c %d",&kind,&num);
		while (getchar()!='\n');
		switch(kind) {
			case 'S':sonzai[0][num-1]=1;break;
			case 'H':sonzai[1][num-1]=1;break;
			case 'C':sonzai[2][num-1]=1;break;
			case 'D':sonzai[3][num-1]=1;break;
		}
	}
	for(c=0;c<4;c++) {
		for(i=0;i<13;i++) {
			if(sonzai[c][i]==0)
				printf("%c %d\n",kindc[c],i+1);
		}
	}
	return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る