2011年9月29日

GoogleCodeJamに挑戦。挫折寸前


お昼休みに激安弁当つつきながらGoogleCodeJamの練習問題というのを解いてみました。

まあ、あれです。昼休みなのに客先サーバの動作が不安定っていう理由で座席に縛り付けられているのです(;-_-) =3
なので気分転換にやってみました。
とりあえずは「数珠繋ぎ」だけですが、
C#で解いたよっ♪
っていう記事が見当たらなかったのでC#で解いてみた結果を載せてみます。

ロジックとしては単純な処理しかしていません。
というか、複雑な処理を組む気はないっす(;´▽`A``

問題としては、

  • 1個以上の電気的スイッチが存在している
  • スイッチの終端には電球がセットされている
  • 終端以外のスイッチの出力には次のスイッチが接続されている
  • スイッチは指を鳴らすという動作によってON/OFFが切り替わる
  • 先頭のスイッチは電力を供給するプラグに接続されている
  • スイッチは電力が供給されている場合のみON/OFFを切り替え、電力が遮断されている場合には変化しない

さて、指をN回鳴らしたとき、K個連結されたスイッチの終端にある電球は光るでしょうか?

脳内で解読した限りこんな感じの要点ではないかと。
興味の出た人はCodeJamのページを読んでみてください。
(練習問題が消えてしまってたらごめんちゃい)

さて、どう解こうかな~、と紙にスイッチの動きを書き出してみたところ
「4個のスイッチ(A-B-C-D)がつながっている場合」
試行回数:スイッチの状態(0:OFF/1:ON)
0:0-0-0-0
1:0-0-0-1
2:0-0-1-0
3:0-0-1-1
4:0-1-0-0
5:0-1-0-1
中略
13:1-1-0-1
14:1-1-1-0@まだ電球は点かない
15:1-1-1-1@ここで電球点灯
16:0-0-0-0@また消える

・・・うん。2進数だ。
2進数でスイッチの数の桁数下位ビットがすべて1の時に点灯するな、これ(^_^;)

てことは。
指を鳴らした数を2進数で変数にセット
その数にスイッチの数だけ下位ビットから1を並べた2進数を論理積する
論理積した結果がスイッチの数とイコールであれば電球は点く
ということではないかと。

紙にちょっと書き出して検算中・・・検算中・・・β(□-□ )
うん。たぶんおっけー

で、こんなソースになりましたとさ

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace GCM_A
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		string Fileadd = string.Empty;
		int counter = 0;
		int[] snapper;
		int[] finguer;
		bool[] light;

		private void button1_Click(object sender, EventArgs e)
		{
			//ファイルを開くボタンを用意して、ファイルを開くと同時に処理スタート

			OpenFileDialog ofd = new OpenFileDialog();

			if (ofd.ShowDialog() == DialogResult.OK)
			{
				Fileadd = ofd.FileName;
			}
			else
			{
				return;
			}

			//FileLoad
			//全データをStringの配列に突っ込む
			string[] lines = System.IO.File.ReadAllLines(Fileadd);

			//先頭に問題数が記載されているのでそれを取り出して各配列の初期値に使う
			counter = int.Parse(lines[0]);
			snapper = new int[counter];
			finguer = new int[counter];
			light = new bool[counter];

			for (int i = 1; i <= counter; i++)
			{
				//スイッチの数と指を鳴らす回数はブランクで繋がっているので数値に変換して取り出す
				snapper[i-1] = int.Parse(lines[i].Split(' ')[0]);
				finguer[i-1] = int.Parse(lines[i].Split(' ')[1]);

			}

			//電球点灯状態を一括チェック
			Calc();

			//結果を出力
			OUTPUT();

			//めでたしめでたし
		}

		private void Calc()
		{

			for (int j = 0; j < counter; j++)
			{
				//指を鳴らした数
				uint a = (uint)finguer[j], x;
				//スイッチの数から論理積に使用するビット列を作る。-1するのを忘れないように
				int n = (int)Math.Pow(2, (snapper[j]));
				uint b = (uint)n-1;
				//指を鳴らした数と1になっているべき値を論理積
				x = a & b;
				//電球が点灯しているかを判断
				if (x==b)
				{
					light[j] = true;
				}
				else
				{
					light[j] = false;
				}

			}

		}


		private void OUTPUT()
		{
			//ファイルに一気に出力する
			StreamWriter sw = new StreamWriter(@"z:\output.txt");
			for (int k = 0; k < counter; k++)
			{
				if (light[k])
				{
					sw.WriteLine("Case #" + (k + 1).ToString() + ": ON");
				}
				else
				{
					sw.WriteLine("Case #" + (k + 1).ToString() + ": OFF");
				}

			}
			sw.Close();
			sw.Dispose();
		}

	}
}


Largeの問題を1秒程度で解いてくれると思っています。
さらに速度を上げるのであれば、、、そうすなぁ~
スイッチの数であらわすことのできる2進数値よりも指を鳴らす回数のほうが小さいときは即座にOFFと判断できるんじゃないかと。

ここまで書いておいてなんですが、
きっと毎回参加される方々はもっと早くプログラム作って解けるんだろうなぁ~と。
C#でビット演算ってあまりやらないよなぁ~と。

こういうの好きな高校とかの先生は次回のテストで
+αのボーナス問題に穴埋めにしてこの問題使いそうだな
と思ったところでお開き。

土曜の予選に参加できるかどうかはサーバが安定するかにかかっている( ̄▽ ̄;)

2011年9月4日

Hello Android、一年近く前から使ってるけど

実際何もコード入力しなくても自動でHelloと言ってくれるAndroidですが、
ちゃんと自力でコードの編集をしてみようと思います。

今更感オーバーフローしてますが、
自分の備忘録的な内容だったりもするので温かい目で。。。
というかそもそも知ってる人はここ読まないですな、お詫びしておきます<(_ _)>

では、自分の作業メモ開始で


「ファイル」→「新規」→「プロジェクト」を選んでいきます。


今回作成するのはAndroidアプリですので、
Androidプロジェクトを選択。テストプロジェクトとの違いはいまいちよく理解してません(;´▽`A``


とりあえずプロジェクトの名前はHelloAndroidWorldとしました。
普通はHelloWorldなんですが、まあ、弄れもんですからъ( ゜ー^)

ビルドターゲットはIS03君に合わせて2.2を選択。
2.3とか3.2の機種欲しいなぁ。。。うん、貧PGには高値の花高嶺の花ですな(わざとです)

そしてパッケージ名ですが、ドメインとかを付けるのが通例みたいです、
もっとも誰かに公開する予定は今のところないので
「bin_pg.android.helloandroidworld」っていう名前にしましたけど

アクティビティーの作成にチェックを入れて、SDKのバージョンはデフォルトのままで行きます。
なぁ~に、上手く行かなかったらもういっかいやり直せばいいだけですから(⌒▽⌒)


はい、とりあえず準備完了です。

このままメニューバーの中にある「実行」(再生ボタンみたいなやつ)を押せば


何で実行するか聞いてくるので、Androidアプリケーションを選んでOK。
すると・・・


はい、無事動きましたヽ(^◇^*)/
何も入力してないけどアクティビティ名を勝手に出してくれたから
Helloって出てる~

で、満足感ちょっと出ていますが、
ちゃんと自力でコード直しましょう、うん。


Eclipseに戻って「src」の中にある、「.java」のソースファイルを開きます。

デフォルトだと画像のようになっていますが、
これの「setContentView(R.layout.main);」の部分が勝手にアクティビティ名を
出してくれているので、ここを修正してみます。

とりあえずテキストでHelloと言って欲しいので、

import android.widget.TextView;

っていうのを追加
(TextViewのロジック作ったあとで、Ctrl+Space押せば自動で作ってくれるけど)

あとは。


TextView _helloAndroidWord = new TextView(this);
_helloAndroidWord.setText("Hello, Android world");
setContentView(_helloAndroidWord);


TextViewのオブジェクトを新規で作成し、
その値はHello, Android worldと設定し、
表示するのは作成したオブジェクトであるとカタカタ入力。

オブジェクト指向言語触ったことある人ならば大体仕組みはわかるはずです。
というか、言語なんて、1ヶ月本気で取り組めば大抵ある程度のレベルまでは到達できるもんです
(なのに古い言語に拘るSIerとか上層部がいるから下請けや平社員は以下略)

package bin_pg.android.helloandroidworld;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroidWorldActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        TextView _helloAndroidWord = new TextView(this);
        _helloAndroidWord.setText("Hello, Android world");
        setContentView(_helloAndroidWord);
    }
}

全体のソースとしてはこんな感じになります。



あとはこれを実行すれば・・・
(再生マークみたいの押すか、Ctrl+F11で)


出来上がり♪
というわけでございます。

さて、GDD2011のAndroidの課題を解くとしましょうかъ( ゜ー^)
では、あとは各自、解散!