こちらの練習問題を解いてみました。
成績としては、二度誤答した後に正解でした。
最終的なコードは以下のとおりです。
短くコンパクトにやるのはスキル的に無理なので、実直に手作業の手順を模倣しています。
#include <stdio.h>
int main(void){
char buf[100];
int group, zaseki_num;
fgets(buf, sizeof(buf), stdin);
sscanf(buf, "%d %d", &zaseki_num, &group);
// 座席リストを生成
// 空席は0、そうでなければ1とするため、0で初期化しておく
int zaseki[100];
for(int i = 0; i < zaseki_num; i++) {
zaseki[i] = 0;
}
// 実際の問題を解く本体はここから
int sum = 0; // 最終的に答えを収納する変数
// グループ数分処理を繰り返す
for(int i = 0; i < group; i++) {
// 入力を受けとる
int ninzu, start;
fgets(buf, sizeof(buf), stdin);
sscanf(buf, "%d %d", &ninzu, &start);
int flag = 1; // 全員座れるかチェック用のフラグ(初期値を1(座れる)とする)
// ひとりずつ座れるかチェックする
for(int j = 0; j < ninzu; j++) {
// startは1始まりだけど、座席リストの添え字は0始まりなので、マイナス1する
// 座席は円卓になっていて、zaseki_num番目の次は1番目の席なので、
// 剰余計算で値をループさせる
// (考えるのがめんどいなら、普通に最終値に達したら0に戻すif文を書いてもよい)
int tmp = (start - 1 + j) % zaseki_num;
// 座席が空いていなければ、フラグを倒して、今回のグループの処理終了
if(zaseki[tmp] != 0) {
flag = 0;
break;
}
}
// フラグが生きていたら、全員座れることを意味する
if(flag == 1) {
// 全員座れることがわかってから、座席リストを更新する
for(int j = 0; j < ninzu; j++) {
int tmp = (start - 1 + j) % zaseki_num;
zaseki[tmp] = 1;
}
// 最終的な答えは、座れたグループの人数を加算する
sum += ninzu;
}
}
// 出力して終了
printf("%d\n", sum);
}
1度目の誤答でどこを修正したかは忘れました。
2度目の誤答の後、入力値を確認したら、座席がループすることを忘れていたのに気づき、座席リストの添え字をループ化させて、正答でした。
座席数が4席なら、1 -> 2 -> 3 -> 4 -> 1 -> 2 -> ...となる。
つまり、ループして5番目の席は、5 % 4 = 1
で求められる。
ループして6番目の席も6 % 4 = 2
となり、剰余でループした座席番号を求められる。
(最終的にはオリジンをずらす必要があることに注意)
終わりに
安易にフラグを使う癖があるので、そこをなんとかしたいなあと思いました