AOJ0594 - Super Metropolis

問題見たとき幅優先かなと思い,実装したら間違ってて悲しくなったのでブログに残しておきます.

AOJ0594

右下と左上方向に移動するときは斜めの道が使えないので,マンハッタン距離の分だけ移動. それ以外は差の絶対値が大きいほうを取る.

コード

// テンプレは省略

signed main()
{
  cin.tie(0);
  ios::sync_with_stdio(false);
  int W, H, N;
  int px, py;
  cin >> W >> H >> N;
  
  // スタート地点
  cin >> px >> py;
  int ans = 0;
  REP(i, N - 1){
    // ゴール地点
    int nx, ny;
    cin >> nx >> ny;
    // 右下と左上に行くときはマンハッタン距離の分だけ移動する
    if (px > nx && py < ny || px < nx && py > ny){
      ans += abs(px - nx) + abs(py - ny);
    } else {
      // 斜めの道を使うときはX,Yそれぞれの差の絶対値が大きいほうを取る
      ans += max(abs(px - nx), abs(py - ny));
    }
    // スタート地点の更新
    px = nx; py = ny;
  }
  print(ans);
  
  return (0);
}

Ubuntu14.04 LTSでIntuos CTL-490を動かす

こんにちは.kurokojiです.最近はUbuntu16.04LTSがリリースされましたね.

さて今回は『Ubuntu14.04でIntuos CTL-490を動かす』という記事ですが,まず

Intuosってなんやねん

ってことですよね.

Intuosとは

Intuos」は、このたび従来のIntuos5からモデルチェンジ したIntuos Proと、従来のペンタブレット製品である BambooがモデルチェンジしたIntuosからなるペンタブレット・ブランドです。プロフェッショナルの使用を前提とした Intuos Proと...
Intuos | Our People | Wacom


ペンタブです

姉になぜか買ってもらいました.ありがとうございます.

Ubuntuで動かす

ここからが本題なのですが,ぼくの持っているIntuos CTL-490Ubuntuで刺しただけでは動きませんし,公式がUbuntu用のドライバを配布してません.なんかwacom製のは動くって聞いたけど動きませんでした.残念.

そこで諦めるわけにはいかないので,なんとか動く方法を探しました.
Ubuntu intuos ctl 490」でググるこんなのがありました.

try to install this driver...
download from the link: http://sourceforge.net/projects/linuxwacom/files/xf86-input-wacom/input-wacom/input-wacom-0.30.0.tar.bz2
unzip the file
open the terminal and go to the directory
run:
・ 4.1 - ./configure
・ 4.2 - make
・ 4.3 - sudo make install
plug the wacom tablet and be happy!
it worked for me!
Ubuntu 14.04. 2 does not recognize my Wacom Intuos tablet draw (ctl-490b)

簡単に訳せば,

  • ここからドライバをDLしてね
  • 解凍してね
  • ターミナル開いてね
  • 解凍したディレクトリに移動して
    • ./configure
    • make
    • sudo make install すると

ペンタブ使えて幸せになれるよ!!!!

ということです. その通りにやって再起動すると動きました.やったぜ.
英語に屈せずにちゃんと読んでよかったです.

GIMPとかも筆圧検知して動いてくれます.筆圧ONにする方法はググってください.
以上です.

カンマ区切りでwhile,for,if文などの条件式を書く時の注意点

自分はこれで苦労したことがあったので備忘録としても書いておくことにする

CやC++ではif(0 < n)などのように括弧内に条件式を書く.
これはwhile(0 < n) for(;i < n;) のようにwhile for文にも同じように書ける.

AOJ等でこんな問題が出る.
カードゲーム | Aizu Online Judge

標準入出力を行うプログラムを作成して下さい。
上記の形式で複数のデータセットが与えられます。nが0のとき入力が終了します。

nの入力の部分だけなら

while (1){
  scanf("%d", &n);
  if (n == 0){
    break;
  }
}

このように書けるだろう.しかしこういう風にも書ける.

while (scanf("%d", &n), n != 0)

後者のほうがコンパクトで見やすい.
因みに,while (scanf("%d", &n), n)と書いても同じような結果になる.
これは,(カンマ)以降に書かれているものを条件式としている.

ただし,このような書き方で注意すべき点がある.
ビデオテープ | Aizu Online Judge

複数のデータセットが与えられます。各データセットは以下のとおりです。
時(整数)分(整数)秒(整数)
入力は、3つの -1 で終わります。

分かった!!さっきの書き方でやると...

while (scanf("%d%d%d", &h, &m, &s), h != -1, m != -1, s != -1)

これでは間違い.この書き方ではs != -1しか条件式として扱ってくれない.
この問題では3つの終了する条件があるので,論理演算子 を使う必要がある.

h-1のときとm-1のときとs-1のときだから...

while (scanf("%d%d%d", &h, &m, &s), h != -1 && m != -1 && s != -1)

一見正解に見えるが,実はこれも間違い.ここで改めて論理演算子の意味を思い出してほしい.
以下はa && b,a || bのときを表している.

&&
a b 真偽
0 0 0(偽)
1 0 0(偽)
0 1 0(偽)
1 1 1(真)
||
a b 真偽
0 0 0(偽)
1 0 1(真)
0 1 1(真)
1 1 1(真)

例えば先程のコードで-1 2 2と入力したとする.
条件は 3つの-1で終わる ことだ.しかしこれではwhileを抜けてしまい終了してしまう.
詳しく見ていこう.

h には-1m には2s には2 が入る.
まずh != -1これは0(偽)になる.m != -1 これは1(真).s != -1も1(真)だ.
論理演算子&&なので表に合わせてみると0 && 1 && 1になり最終的に0になる.
0ということはwhile文を抜けることになる.3つとも-1ではない のにだ.

なので正解は

while (scanf("%d%d%d", &h, &m, &s), h != -1 || m != -1 || s != -1)

これなら0 || 1 || 11になり条件に合わずに抜けることが無くなる.
考えてみれば当然だが,,(カンマ)で区切らない方法で書くと

while (1){
  scanf("%d%d%d", &h, &m, &s);
  if (h != -1 && m != -1 && s != -1){ // ||じゃなくて&&
    break;
  }
}

となり&&で書くのでカンマ区切りと逆になってしまう.
僕のようなプログラミング初心者が躓いてしまい,AOJでWAを出される羽目になってしまうので注意していただきたい. (因みにこの問題ではチェックが甘いのでh != -1だけでも通る)

何か間違っている点があればコメント等で教えていただけると幸いです.