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

2012年5月23日水曜日

C++を勉強中・・・ orz

std::shared_ptr使っているときにthisポインタを扱いたいときは
std::enable_shared_from_this<クラス名>を継承して,
shared_from_this()を使用して取得する・・・であっているのかな・・・.

#include <iostream>
#include <memory>

class Student : public std::enable_shared_from_this<Student>
{
public:
    Student(std::string name, int first_score, int second_score)
        : name_(name), first_score_(first_score),
          second_score_(second_score) {}
    ~Student() { std::cout << "delete " << name_ << std::endl; }

    void printScore() {
        std::shared_ptr<Student> ptr = shared_from_this();
        std::cout << name_ << " : "
                  << first_score_ + second_score_ << std::endl;
    }
    std::shared_ptr<Student> getSharedPointer() {
        // これだとやばい・・・
        // return  std::shared_ptr<Student>(this);
        return  shared_from_this();
    }
private:
    std::string name_;
    int first_score_, second_score_;
};

int main()
{
    auto student = std::make_shared<Student>("Miyanaga", 5200, 24000);
    auto it = student->getSharedPointer();

    it->printScore();
    sleep(1);

    return 0;
}

2012年1月14日土曜日

らららMeCab

MeCabをC++で使ってみました。
ちょっと品詞のところは強引です<-
なんか任意のIDが割り当てられるみたいなんで、
それを利用すれば少しは強引じゃなくなるのかな・・・<-

下記のソースコードは形態素の品詞が
名詞か動詞であれば出力するようにしてるはず・・・<-
まだ仕様とか確認してない<-

// g++ mecab_test.cc -std=gnu++0x -lmecab

#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include <mecab.h>

int main(int argc, char **argv) {
  std::string text = "まずはそのふざけた幻想をぶち殺す";
  std::shared_ptr<MeCab::Tagger> tagger(MeCab::createTagger(argc, argv));
  const MeCab::Node *node = tagger->parseToNode(text.c_str());

  std::cout << text << std::endl;

  for (; node; node = node->next) {
    if (strstr(node->feature, "名詞,")  != NULL
        || strstr(node->feature, "動詞,")  != NULL) {
      std::cout << std::string(node->surface, node->length);
    }
  }

  std::cout << std::endl;

  return 0;
}
出力:

まずはそのふざけた幻想をぶち殺す
ふざけた幻想殺す



// 2012年1月14日にちょっと修正<-




2011年12月25日日曜日

一致したなかで最大値のものだけを選択するとこうなるのか・・・ orz



最大値をとったのは次の評価では除外してます
手順違いな棋譜は得られてますね・・・
石は認識してくれてるみたい<-
う〜ん やっぱちゃんと関連するものをちゃんと読んで再出発するべきだね

2011年12月24日土曜日

んな〜 休憩終了!<-

っで,そこで画像から棋譜を作成することを試みみました.
パターンマッチング時に使用する辞書ベクトルは
テストデータとは別のもの(書体も違うもの)を使用しました.
用いる尺度は部分空間法で使われる類似度の辞書ベクトルの数を1にした




を使いました(こんなふうに使っていいんだろうか<-).
ここで, は入力ベクトル, は辞書ベクトルです.

使用した棋譜画像は












これです.
結果は悲惨なものになりました<-
方向を修正してトリミングし,パターンマッチングのために
拡大した画像が以下の画像です.
若干?二値化しています.












これからパターンマッチングにより得られた棋譜がこれです・・・.
いろいろ間違ってます.
パターンマッチングとして,類似度が最大のものを候補として
いるので,同じ手を選んでしまっているものもあります<-
う〜ん,テスト画像とは違う書体の数字を辞書ベクトルで使用してるんで,
すこぶる良くないですね・・・(;・∀・)



今後の課題は・・・

  • 正解率あげないとヤバい、使い物にならない<-
  • そのためには画像の方向を修正するときや拡大するときにきれいに?処理したい
  • 辞書ベクトルの数とか,ちゃんと部分空間法を扱いたい<-
  • 判別分析の方がいいのかも、まだ何もやってないけど<-
  • 直線や円の検出をやって盤のサイズや石を検出して,正解率を向上させたい・・・<-
  • コウの時に棋譜の下側に書かれるやつも処理できるようにしたい
いつになるかわからないけど,
また休憩したときに改善したいと思いますヽ(*゚д゚)ノ
ってなわけで休憩お〜わり<-
こんなんだから,心が細いんだろうな・・・

あー昨日の間違ってた

何故か拡大後で補完してました<-
直すとこんな感じ・・・
微妙すぎる・・・ orz
あ、トリミング機能付けてみました.


2011年12月23日金曜日

引き続きちょっと休憩

昨日に引き続いてちょっと休憩してみます<-
今日は画像の拡大についてやってみました.
これはただ倍率を元の座標にかければ拡大できるんですが,
単にすると下のように薄ーくなった画像が出来上がってしまいます orz
これは昨日の出力画像において縦横1.5倍した奴です・・・

っで,これじゃまずいので何かいろいろな補完方法があるらしい<-
けどあんまり興味はないので<-
直感的な4近傍の平均を用いる補完方法を追加してみました.
そうすると以下のように若干ましになった画像が得られました.
ただ濃くなっただけな気がするけど・・・.
たぶんもうちょっとだけ休憩しますヽ(*゚д゚)ノ<-





ちょっと休憩

久しぶりにラベルがProgramsな投稿
画像の回転をやってみました(画像?ここゲーム関連じゃ・・・)

問題設定?は以下のような斜めになってる棋譜画像を
正しい方向に元に戻すことにしました.
ここではPNG形式のファイルになってるんですが,
実際にはPGM形式のファイルを使用しています orz
あ、この棋譜画像は棋譜画像作成ツールを使用させて頂いて作成したものを
テスト用にわざわざ10度程度回転させたものです.




ここでは超高等テクニックであるHough変換を使って直線を検出したりはせず<-
棋譜画像で傾いているのは大抵この2つのパターンなので
場合分けして左上と右上の頂点を調べて,
そこから傾いている角度を算出して,
直したものを結果として出力画像として出力するものを作成してみました.
素晴らしく汎用性皆無のコードを最後に貼っつけて置きます・・・.
使い方はコマンドライン引数に対象とするPGM形式のファイルパスと
結果を出力するPGM形式のファイル名を指定する感じで動きます.
こんなコード書いていて大学生として恥ずかしくないわけがない<-
githubにあげられるようなコード書けるように頑張ろう・・・<-

あ,っでこのコードによる出力は以下のようになりました.
これもPNG形式の画像となっていますが,実際はPGM形式の画像です・・・ orz
う〜ん、ちゃんと正しい方向な棋譜が得られていることがわかります.ヽ(*゚д゚)ノ
意外に角を打たれていても良い感じですね<-
けど,ただ回転行列を用いているだけなので,画質が劣化してると思います.Σ(´∀`;)
あと,トリミング機能あったほうが良いかも<-

 


まとめると<-
  • Hough変換使わなくても簡単な棋譜の方向の修正はたぶんできる.
  • 単純に回転行列使ってるだけじゃ画質が劣化する.



#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <cstdlib>
#include <cmath>

class Image {
 public:
  Image(char *file_name, char *output_file_name) { init(file_name,
output_file_name); }
  void init(char *file_name, char *output_file_name);
  void doCorrect();
  void outputImage();
  
 private:
  std::string file_type_;
  std::string file_comment_;
  int img_height_;
  int img_width_;
  int max_value_;
  std::vector<std::vector <int> > img_data_;
  std::string output_file_name_;
};

void Image::init(char *file_name, char *output_file_name) {
  output_file_name_ = output_file_name;

  std::ifstream fin(file_name);
  if (!fin) {
    std::cerr << "file not found" << std::endl;
    exit(1);
  }
    
  fin >> file_type_;
  if (file_type_ != "P2") {
    std::cerr << "file not found" << std::endl;
    exit(1);    
  }
  
  // コメント処理 コメントが1行あると仮定
  fin.ignore();
  getline(fin, file_comment_);
   
  fin >> img_width_ >> img_height_ >> max_value_;
  img_data_.resize(img_height_);
  for (int i = 0; i < img_height_; i++) {
    img_data_[i].resize(img_width_);
    for (int j = 0; j < img_width_; j++) {
        fin >> img_data_[i][j];
    }
  }
  fin.close();
}

void Image::doCorrect() {
  int x_top_left = -1;
  int y_top_left = 0;
  int x_top_right = -1;
  int y_top_right = 0;

  // 左上の頂点を探索
  for (int i = 0; i < img_height_; i++) {
    for (int j = 0; j < img_width_; j++) {
      if (img_data_[i][j] < max_value_ / 2) {
        x_top_left = j;
        y_top_left = i;
        break;
      }
    }
    if (x_top_left >= 0) {
      break;
    }
  }
  
  // 反時計回りに傾いていると考えられる場合
  if (x_top_left > img_width_ / 2) {
    x_top_right = x_top_left;
    y_top_right = y_top_left;
    int min_distance = img_width_;
    for (int i = 0; i < img_height_ / 2; i++) {
      for (int j = 0; j < img_width_ / 2; j++) {
        if (img_data_[i][j] < max_value_ / 2 && j < min_distance) {
          min_distance = j;
          x_top_left = j;
          y_top_left =  i;
        }
      }
    }   
  }
  else {
    int max_distance = 0;
    for (int i = 0; i < img_height_; i++) {
      for (int j = 0; j < img_width_; j++) {    
        if (img_data_[i][j] < max_value_ / 2 && j > max_distance) {
          max_distance = j;
          x_top_right = j;
          y_top_right =  i;
        }
      }
    } 
  }
  
  double theta = atan2((double)(y_top_right - y_top_left),
                       (double)(x_top_right - x_top_left));

  std::vector<std::vector<int> > correct_img_data(img_height_,
 std::vector<int>(img_width_, max_value_));
  for (int i = 0; i < img_height_; i++) {
    for (int j = 0; j < img_width_; j++) {
      int x_correct = j * cos(theta) + i * sin(theta);
      int y_correct = -j * sin(theta) + i * cos(theta);
      
      if (x_correct >= 0 && x_correct < img_width_
          && y_correct >= 0 && y_correct  < img_height_) {
          correct_img_data[y_correct][x_correct] = img_data_[i][j];
      }
    }
  }
  img_data_ = correct_img_data;
}

void Image::outputImage() {
  std::ofstream fout(output_file_name_.c_str());
  fout << "P2" << std::endl;
  fout << file_comment_ << std::endl;
  fout << img_width_ << " " << img_height_ << std::endl;
  fout << max_value_ << std::endl;

  for (int i = 0; i < img_height_; i++) {
    std::copy(img_data_[i].begin(), img_data_[i].end(),
              std::ostream_iterator<int>(fout, "\n"));
  }

  fout.close();
}

int main(int argc, char **argv) {
  if (argc == 1) {
    std::cerr << "enter a pgm file on the command line" << std::endl;
    return 1;
  }
  else if (argc == 2) {
    std::cerr << "enter a output file name on the command line" << std::endl;
    return 1;    
  }
  
  Image img(argv[1], argv[2]);
  img.doCorrect();
  img.outputImage();

  return 0;
}
2011年12月25日にちょっと修正<-

2010年11月9日火曜日

AOJ Volume 5 Problem 0502 : Dice

#include<iostream>

int main()
{
    for (int n; std::cin >> n, n;)
    {
        int s = 1, d[] = {2, 3, 5, 4, 1}, i, t, a, b;

        for (i = 0; i++ < n; s += d[4])
        {
            char c[9], e;
            std::cin >> c;
            e = *c;
            a = 0;
            
            if (e != 'R' && e != 'L')
            {
                e == 'N' ? a = 2, b = 0 : e == 'E' ? a = 1, b = 3 
                     : e == 'W' ? a = 3, b = 1 : b = 2;
                d[a] = d[4];
                d[4] = d[b];
                d[b] = 7 - d[a];
            }
            else
            {
                e == 'R' ? : a = 2;
                t = *d;
                *d = d[1 + a];
                d[1 + a] = d[2];
                d[2] = d[3 - a];
                d[3 - a] = t;
            }
        }
        std::cout << s << '\n';
    }

    return 0;
}
バリンバリンの自分なりのショートコーディング.
納得の331 Bytesです.

問題はサイコロに関する問題なんですが,
回転の種類を大きく2つに分けることができて,
関数化できるので,上記のようなショートコーディングが行えてます.

2010年11月3日水曜日

行列と転置行列の積


#include <iostream>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
using namespace std;
using namespace boost::numeric::ublas;

int main()
{
    matrix<int> A(2, 2), B(2, 2);

    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            A(i, j) = i * 2 + j + 1;
            B(i, j) = i * 2 + j + 2;
        }
    }

    cout << A << endl;
    cout << B << endl;
    cout << prod(A, trans(B)) << endl;

    return 0;
}

/* execution result
[2,2]((1,2),(3,4))
[2,2]((2,3),(4,5))
[2,2]((8,14),(18,32))

*/ 


上のプログラムは下記の計算を行っています.


スッキリ書けて素晴らしい.d(゚∀゚)b

2010年11月1日月曜日

今年一番不真面目に取り組んじまった

    
 テスト画像           圧縮データによる復元画像

一目で荒さがわかりますね.ニューラルネットには砂時計型(64-16-64)を使用しています.
プログラムは下の本の5章に書かれていることを参考に実装しました.


学習回数は上の画像では1000回です.
問題の圧縮率は,元画像は192.1 KB,圧縮データは49.1 KBなので,約25.6%となっています.
圧縮データの構成は,画像のヘッダー情報,中間層と出力層の数,中間層と出力層間の重み,
出力層の各バイアス,中間層の各出力です.

GUIも作成し,内容は圧縮したいデータをドラッグ&ドロップしたら圧縮データが作成され,
その復元画像が表示されるものです.

カラー画像のPNSR(peak signal-to-noise ratio)ってどう算出するのかわからないんだけど,
MSEをRGBに対してそれぞれ求めて足し合わせたものを3で割った物を使って,
PNSRを求めると約26.8 dBでした.もうちっと上げたいものですね.

縦に線が入ってる理由は,おそらく入力を
左上から右に順々に繰り返しているからだと考えられます.

改善+オリジナリティが必要ですが,また発表ではミスりましたが,
質疑応答もしっかりと出来ませんでしたが,
俺の本命はゲーム情報学なので,これからはそっちに熱を注ぎたいと思います.

2010年10月1日金曜日

ポインタを保持するvector


#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int num = 5;
    vector<int*> v;

    v.push_back(&num);
    cout << "num = " << num << endl;
    cout << "*v[0] = " << *v[0] << endl;

    *v[0] = 15;
    cout << "num = " << num << endl;
    cout << "*v[0] = " << *v[0] << endl;

    return 0;
}

// execution result
/*
num = 5
*v[0] = 5
num = 15
*v[0] = 15

*/ 

個人的なメモ.
jk当然可能.

28/01/11 追記
この方法はよく考えたらよくないですね.
スコープ外れてもdeleteしてくれないし・・・.
ごめんなさい.
boostのshared_ptrを使ったほうが良いですね.

2010年9月22日水曜日

AOJ Volume 5 Problem 0505 : Questionnaire


#include<iostream>
using namespace std;

int main()
{
    for (int n, m, i, j, c; cin >> n >> m, i = n;)
    {
        int r[101] = {0};
        for (; i--;)
            for (j = 0; ++j <= m; !c ? : r[j]++)
                cin >> c;

        for (i = n + 1, c = 0; --i;)
            for (j = 0; ++j <= m;)
                r[j] != i ? : cout << j << (++c == m ? '\n' : ' ');
    }

    return 0;    
}

若干ショートコーディング気味のコード.
ショートコーディングを自分なりにちゃんとやると208 Bytesになりました.

2010年9月7日火曜日

モンテカルロ法を用いた円周率の算出風景

モンテカルロ法を用いた円周率の算出中の画像
実際はリアルタイムで点が増えてきます
Qtの練習第二弾として, モンテカルロ法を用いた円周率の算出風景?を
可視化できるものを作成してみました.

リアルタイムで点が増えて行くのはまぁまぁ気持ち良くないですが,
なかなか正確な値に近づかないのが,もどかしい気持ちにさせます.
ちなみに第一弾の5五将棋のGUIは未だに作成中です.
決して逃げた訳じゃないと思う・・・。

作成手順は
1.  正方形なウィンドウを作成し内接円を描く.
2. ウィンドウサイズ内にランダムに点を打ち,円の内外判定を行う.
 今回はupdate(x, y, width, height)で特定の場所を更新できることを用いました.
3. 4×円の内側 (円周上も含める) に入った点の数 / 点を打った数を中央に表示する.
4. 2と3を繰り返す.

っな感じです.
上の例では 内側の点は青く, 外側の点は赤くしてます.

2010年9月1日水曜日

AOJ Volume 1 Problem 0196 : Baseball Championship


#include <iostream>
using namespace std;

int main()
{
    int n;
    while (cin >> n, n)
    {
        char name[10];
        int win[10] = {0};
        int lose[10] = {0};

        for (int i = 0; i < n; i++)
        {
            cin >> name[i];
            for (int j = 0; j < n - 1; j++)
            {
                int s;
                cin >> s;
                if (s == 0)
                    win[i]++;
                if (s == 1)
                    lose[i]++;
            }
        }

        for (int i = n - 1; i > -1; i--)
            for (int j = 0; j < n - i; j++)
                for (int k = 0; k < n; k++)
                    if (win[k] == i && lose[k] == j)
                        cout << name[k] << endl;

    }

    return 0;
}

本来,ソートを行うべきですが,入力されるチーム数が最大10と少ないため,
ソートせずに,全勝のチーム,1敗 0引き分けのチームといった順番にヒット?させています.
絶対無駄な処理があり,実行速度は若干遅いだろうと思いますが,
コード自体がスッキリするので,これもありなんじゃないかと思います.

2010年8月27日金曜日

なんちゃってランレングス圧縮


#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
using namespace std;

void Compress(string inputFileName, string outputFileName);
void UnCompress(string inputFileName, string outputFileName);

int main(int argc, char** argv)
{
    if (argc < 3)
        return 0;

    if (! strcmp(argv[1], "nz"))
    {
        Compress(argv[2], argv[2]);
        cout << "Compressed file is " << argv[2] << ".nz" << endl;
    }
    else if (! strcmp(argv[1], "unz"))
    {
        string outputFileName(argv[2]);
        string::size_type index = outputFileName.rfind(".nz");
        if (index != string::npos)
            outputFileName = "Unz" + outputFileName.substr(0, index);
        else
            return 1;

        UnCompress(argv[2], outputFileName);
        cout << "Extracting file is " << outputFileName << endl;
    }

    return 0;
}

void Compress(string inputFileName, string outputFileName)
{
    outputFileName += ".nz";
    ifstream fin(inputFileName.c_str(), ios::in | ios::binary);
    ofstream fout(outputFileName.c_str(), ios::out | ios::binary);

    if (! fin || ! fout)
        return;

    int delimiterPre = 0;
    int delimiterPost = 0;
    int rawByte, preByte, num = 0;
    preByte = fin.get();

    while ((rawByte = fin.get()) != EOF)
    {    
        if(rawByte != preByte || num == 255)
        {
            if (num > 1)
            {
                fout.write((char*) &delimiterPre, sizeof(char));
                fout.write((char*) &delimiterPost, sizeof(char));
                fout.write((char*) &num, sizeof(char));
            }
            fout.write((char*) &preByte, sizeof(char));
            preByte = rawByte;
            num = 1;
        }
        else if (rawByte == preByte)
            num++;

    }
    if (num > 1)
    {
        fout.write((char*) &delimiterPre, sizeof(char));
        fout.write((char*) &delimiterPost, sizeof(char));
        fout.write((char*) &num, sizeof(char));
    }
    fout.write((char*) &preByte, sizeof(char));

    fin.close();
    fout.close();
}

void UnCompress(string inputFileName, string outputFileName)
{
    ifstream fin(inputFileName.c_str(), ios::in | ios::binary);
    ofstream fout(outputFileName.c_str(),ios::out | ios::binary);
    if (! fin || ! fout)
        return;

    int rawByte, preByte;
    preByte = fin.get();

    while ((rawByte = fin.get()) != EOF)
    {
        if (preByte == 0 && rawByte == 0)
        {
            while ((preByte = fin.get()) == 0)
                fout.write((char*) &preByte, sizeof(char));

            rawByte = fin.get();
 
            for (int i = 0; i < preByte; i++)
                fout.write((char*) &rawByte, sizeof(char));

            if ((preByte = fin.get()) == EOF)
                break;
        }
        else
        {
            fout.write((char*) &preByte, sizeof(char));
            preByte = rawByte;
        }
    }

    if (preByte != EOF)
         fout.write((char*) &preByte, sizeof(char));

    fin.close();
    fout.close();
}


上のコードでの実行に起因する損害に関して責任を持ちません.
 あと,世の中の高専生はもっと賢いです.こんなコードは書きません.

上のコードは1バイト単位でデータのランレングス圧縮を行うようなものです.
俺,実は学校でデータ圧縮に関して何かやらなきゃいけない立場なようで,
バイナリでデータを扱う練習がてら作ってみたものなんですが,
圧縮になるときと,ならないときが出てきちゃう,ダメダメなものになってしまいました.

ここで簡単にランレングス圧縮の説明ー.
文字列Zeeeeeeeingってなのを考えたとき,
連続した文字に注目して文字列中に数字が出てこないとして,
数字+文字で数字の数だけ文字があることを表すとすれば
文字列Zeeeeeeeingのeは7eと省略でき,最終的に
Z7eingとすることで文字列長を10から6に圧縮でき,
確かこんな操作を行う圧縮をランレングス圧縮と呼ばれる(たぶん).

で,上のコードも1バイト読み取ってそんな操作を行っているんですが,
デリミターで問題?が生じた結果, 圧縮にならないときが生じてしまいました.
ここでデリミターは繰り返しがある位置を表す区切り文字のこととします.
上のコードではデリミターを0x0000にしています.
で0x0000 (文字の繰り返し回数) (繰り返し文字) と 4バイトでランレングス圧縮を試みてるんですが,
これだと5回以上連続で文字が出現しない限り,圧縮にならないことになります.
そこで,4回以下はそのまま出力すればいいやと思っていたら,
0x0000 の表記があった場合それがデリミターか単なる?0x0000なのか
区別がつかなくなることに気がつき,どうしようもなく,そのままにしてあります.
おそらく2回連続は良くある?ので3回以上はランレングス圧縮するようにすれば良くなるかもですが・・・.
で,最終的に上のコードが言いたいことは,1バイト単位でやってもそんな圧縮にならんってことです(たぶん).

圧縮に関しては, 卒研より相当締切り日的なものが近く,
どうにかしなければならないので,今からで遅すぎますが,
どうにかして行きたいと思います.

ちなみに上のコードでC++で書いたHelloを出力する
実行ファイルを圧縮してみたところ,7783 bytesとから 6365 bytesと
見事に微妙に圧縮されました.
他のファイルではデリミッター問題?で元より増加してしまいました(ダメダメです).

使い方
コンパイル
g++ -o RunLength このコードファイル名.cpp

圧縮 (例としてhelloファイルの圧縮)
./RunLength nz hello
でhello.nzってな圧縮ファイルが作成される.

解凍(伸長)
./RunLength unz hello.nz
でUnzhelloってな解凍ファイルが作成される.

helloとUnzhelloが同じファイルであることを切に願います.

2010年8月19日木曜日

AOJ Volume 1 Problem 0105 : Book Index

#include <iostream>
#include <string>
#include <set>
#include <map>
using namespace std;

int main()
{
    int n;
    string str;
    map<string, set<int> > m;
    map<string, set<int> >::iterator p;

    while (cin >> str>> n)
        m[str].insert(n);

    for (p = m.begin(); p != m.end(); p++)
    {
        cout << p->first << endl;
        set<int>::iterator q = (p->second).begin();
        for (; q != (p->second).end(); )
        {
            cout << *q;
            cout << (++q != (p->second).end() ? ' ' : '\n');
        }
    }

    return 0;
}
 一つの書き方としてありかも.
あと, 書き方を変えてみました. こっちの方が一般的?
確かFuegoも書き方はこんな感じだったと思う.
いろいろ見て, 見習っていきたい.

2010年8月17日火曜日

AOJ Volume 5 Problem 0501 : Data Conversion


#include <iostream>
#include <map>
using namespace std;

int main() {
    int n;
    while (cin >> n, n) {
        map<char, char> conversion;
        map<char, char>::iterator p;
        for (int i = 0; i < n; i++) {
            char pre, post;
            cin >> pre >> post;
            conversion[pre] = post;
        }

        cin >> n;
        for (int i = 0; i < n; i++) {
            char ch;
            cin >> ch;
            p = conversion.find(ch);
            cout << (p == conversion.end() ? ch : p->second);
        }
        cout << endl;
    }

    return 0;
}


mapを使ってキーが見つからない場合はマップの末尾を指す反復子を返すことを利用している.
全然,コンピュータ囲碁プログラムの話題ができなくて,テーマ変わっちゃいそうですが,今必死に考え中です・・・.

AOJ Volume 0 Problem 0051 : Differential Ⅱ


#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
    int n, min;
    cin >> n;

    for (int i = 0; i < n; i++) {
        string str;
        cin >> str;
        sort(str.begin(), str.end());
        min = atoi(str.c_str());
        sort(str.rbegin(), str.rend());
        cout << atoi(str.c_str()) - min  << endl;
    }

    return 0;
}

ショートコーディングすると,241byteでC++の中では一番短いみたいですが,
Cで書かれた一番短いコードとは100byte近く離されてる・・・。

AOJ Volume 1 Problem 0157 : Russian Dolls


#include <iostream>
#include <map>
using namespace std;

int main()
{
    int n, r, h;
    while (cin >> n, n)
    {
        // longest increasing subsequence: lis
        int k = 0, lis[200] = {0};
        multimap<int, int> dolls;

        for (int i = 0; i < 2; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> r >> h;
                dolls.insert(pair<int, int>(r, h));
            }
            if (! i)
                cin >> n;
        }

        for (multimap<int, int>::iterator p = dolls.begin();
             p != dolls.end(); p++)
        {
            for (multimap<int, int>::iterator q = dolls.begin();
                 q != p; q++)
            {
                if (p->first > q->first && p->second > q->second)
                {
                    if (lis[distance(dolls.begin(), p)] 
                        <= lis[distance(dolls.begin(), q)])
                    {
                        lis[distance(dolls.begin(), p)] 
                            = lis[distance(dolls.begin(), q)] + 1;
                        if (k < lis[distance(dolls.begin(), p)])
                            k = lis[distance(dolls.begin(), p)];
                    }
                }
            }
        }
        cout << k + 1 << endl;
    }

    return 0;
}

I fill my spare time on the Web site of "AOJ".
What's "AOJ?"
AOJ stands for Aizu Online Judge.

他にもオンラインジャッジはUva Online Judgeなどありますが,
会津大学のオンラインジャッジは,パソコン甲子園などの日本語の問題も幅広く取り扱っていて
高校, 高専, 大学のプログミング部や同好会は結構使っているんじゃないかなぁと思います.
コードを書いて基礎体力?とアルゴリズムを勉強していきたい人には打って付けだと思います.

上のコードはDPを用いて解いたものです.
最長増加部分列を求めるような問題でした.
たぶん,コードを見ればその人との力量が分かると思うんで,
今こんな感じですが, 今後も励んでちっとでも美しく書けるように頑張りたいと思います.