suzu-log/g86

 | 

2008-04-21

TopCoder SingleRoundMatch 398 Div.2 250問題ってこんなの

00:31 | TopCoder SingleRoundMatch 398 Div.2 250問題ってこんなの - suzu-log/g86 を含むブックマーク はてなブックマーク - TopCoder SingleRoundMatch 398 Div.2 250問題ってこんなの - suzu-log/g86

つい先週参加したばかりで自分の中で盛り上がってるTopCoderですが、SingleRoundMatch(SRM)のDiv2(Rating1200点以下の人用)の一番簡単な250点問題はこんなのです。*1

// PROBLEM STATEMENT

//

You are given numbers A0, X, Y, M and n.

Generate a list A of length n according to the following recurrence relation:

A[0] = A0

A[i] = (A[i - 1] * X + Y) MOD M, for 0 < i < n

Return the minimal absolute difference between any two elements of A.


DEFINITION

Class:MinDifference

Method:closestElements

Parameters:int, int, int, int, int

Returns:int

Method signature:int closestElements(int A0, int X, int Y, int M, int n)

で、次のメソッドを完成させるわけです。

public class MinDifference {
        public int closestElements(int A0, int X, int Y, int M, int n) {

        }
}

そこのid:Hashid:diouf21、楽しそうな気がしませんか?

そうそう、TopCoderをやるときには必ずプラグインを入れてから自分の好きなエディタでやりましょう。問題文がローカルに残らないと復習しにくいからね。

プラグイン導入はTopCoderでCodeProcessor+TZTester+FileEdit - Gulfweedのページにわかりやすい解説があります。

LiosK問題2

23:51 | LiosK問題2 - suzu-log/g86 を含むブックマーク はてなブックマーク - LiosK問題2 - suzu-log/g86

サンプルが人数60人に対して問題数が10、さらに問題の上限と下限が全部同じなので、Greedyに全部やれば埋まるんじゃね?と思った。

#include <iostream>
using namespace std;

#define Fill(a, b) memset(a, b, sizeof(a))

int main() {

  bool opinion[60][10] = {
    {true,  true,  true,  true,  false, true,  true,  false, true,  true },
    {true,  false, true,  true,  false, true,  false, true,  true,  true },
    {false, true,  true,  true,  true,  true,  false, true,  true,  true },
    {true,  false, true,  true,  false, true,  false, false, true,  false},
    {true,  true,  false, false, false, true,  false, false, true,  true },
    {true,  false, true,  false, false, true,  false, false, true,  false},
    {true,  false, false, true,  false, false, false, false, false, true },
    {false, false, true,  true,  false, false, true,  true,  true,  false},
    {false, true,  false, false, true,  true,  true,  false, true,  true },
    {true,  false, true,  true,  true,  true,  true,  true,  false, true },
    {false, true,  false, false, true,  false, true,  false, true,  true },
    {true,  true,  true,  false, true,  false, true,  false, true,  true },
    {false, true,  true,  true,  true,  false, true,  true,  true,  true },
    {false, false, true,  false, false, false, true,  true,  true,  true },
    {true,  true,  true,  true,  false, true,  false, false, true,  false},
    {false, false, true,  false, false, true,  true,  false, false, true },
    {true,  true,  false, true,  false, true,  true,  true,  true,  true },
    {true,  false, false, false, true,  false, false, false, false, true },
    {false, true,  true,  true,  false, false, false, false, false, false},
    {false, true,  true,  false, false, false, false, true,  true,  false},
    {false, true,  false, false, false, false, false, false, true,  false},
    {true,  false, true,  true,  true,  false, true,  true,  false, true },
    {false, false, false, false, true,  true,  false, true,  true,  true },
    {false, true,  true,  true,  false, false, true,  true,  true,  true },
    {true,  false, false, false, true,  false, true,  true,  true,  false},
    {true,  true,  true,  true,  true,  true,  true,  false, false, false},
    {true,  false, true,  false, true,  false, true,  false, true,  true },
    {false, false, true,  false, false, false, false, false, false, true },
    {true,  false, true,  true,  false, true,  true,  false, false, true },
    {true,  true,  true,  true,  true,  true,  false, true,  false, true },
    {false, true,  true,  false, true,  false, false, false, false, true },
    {true,  true,  true,  true,  false, false, true,  true,  true,  true },
    {false, true,  true,  false, false, true,  false, false, true,  false},
    {true,  false, false, true,  true,  false, true,  false, true,  false},
    {true,  false, false, true,  true,  true,  true,  false, true,  true },
    {true,  true,  false, true,  true,  false, false, false, true,  true },
    {true,  false, true,  false, true,  true,  true,  false, true,  true },
    {true,  true,  false, false, true,  true,  true,  true,  true,  false},
    {true,  true,  false, false, true,  false, true,  true,  true,  false},
    {false, true,  true,  false, false, false, false, true,  false, true },
    {true,  true,  true,  true,  false, true,  true,  false, true,  true },
    {true,  false, true,  true,  true,  false, true,  true,  true,  true },
    {false, true,  false, false, false, true,  true,  false, true,  true },
    {true,  false, true,  true,  false, false, false, true,  false, true },
    {false, false, false, false, false, false, true,  false, true,  false},
    {false, false, true,  false, false, true,  true,  true,  true,  true },
    {false, true,  true,  true,  true,  true,  false, false, false, false},
    {true,  true,  false, false, true,  false, true,  false, false, false},
    {true,  false, true,  true,  false, false, true,  true,  false, true },
    {false, false, false, false, false, false, false, true,  false, true },
    {false, false, false, false, true,  true,  false, false, true,  false},
    {true,  true,  true,  true,  true,  true,  false, false, true,  false},
    {true,  true,  true,  true,  true,  true,  false, true,  true,  false},
    {false, false, false, true,  true,  false, false, false, false, true },
    {true,  false, false, false, false, true,  false, true,  true,  true },
    {false, false, false, false, false, false, true,  true,  false, true },
    {false, false, true,  false, true,  false, true,  true,  false, true },
    {true,  false, true,  true,  true,  true,  true,  false, true,  true },
    {true,  true,  false, false, true,  false, true,  true,  true,  true },
    {false, false, false, true,  true,  false, true,  true,  false, true }
  };

  int cap[10][2] = {
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5},
    {3, 5}
  };

  int mem[10];
  bool used[60];
  int wariate[60];
  Fill(used, false);
  Fill(mem, 0);
  Fill(wariate, -1);

  for (int i=0; i<60; i++) {
    for (int j=0; j<10; j++) {
      if (opinion[i][j] && mem[j] < cap[j][1] && wariate[i] == -1) {
	mem[j]++;
	used[i] = true;
	wariate[i] = j;
      }
    }
  }

  bool allFull = true;
  for (int j=0; j<10; j++) {
    if (mem[j] < cap[j][1]) {
      cout << "Exp No." << j << " is not satisfied : " << mem[j] << endl;
      allFull = false;
    }
  }
  if (allFull) {
    cout << "All Experiments are filled by max capacity";
  }

  return 0;
}

実行結果

/Users/suzukitomohiro/srm% ./a.out

All Experiments are filled by max capacity

サンプルデータなら、偶然全部の実験に5人を割り振れたよ!

めでたしめでたし?

LiosK問題

21:48 | LiosK問題 - suzu-log/g86 を含むブックマーク はてなブックマーク - LiosK問題 - suzu-log/g86

この問題はどう解けばいいんだ? / LiosK-free Blog

この実験に割り当てる問題で、最大で人数を11人、実験の数を20、一つの実験の容量を10と仮定する。

次のrecurという関数が表す状態を考える。状態の数は最大で(2の10乗*20*10)存在する。

recurは次の引数をとり、この状態のときに条件を満たす実験の数が最大でいくつできるかを返す。

  • 1. 誰が既に実験に割り当てられたかのビットmask
  • 2. 現在の実験番号expNum
  • 3. 現在の実験に割り当てられる残り人数curCap

実験番号はそれぞれの実験に割り当てられた番号で0からはじまる。

誰が既に実験に割り当てられたかというmaskという引数は人数の数分の幅を持つビットで、例えば4人のとき(0, 1, 2, 3番目の人がいるとして)

  • maskの値が1だったら2進数で0001なので0番目の人はもう実験に割り当てられないということ。
  • maskの値が6だったら2進数で0110なので2番目の人と1番目の人は実験に割り当てられないということ。

以上の引数を持つrecurは自分自身を再帰的に呼び出して、さまざまな状態に移ったときの最大値を使って自分が返す値を求める。

  • 1. 現在の実験にさらに人を割り当てる
  • 2. 現在の実験に人を割り当てるのをやめ、次の実験に人を割り当てはじめる

ちなみに

  • 求めたい値はrecur(0<既に割り当てられた人を表すビット>, 0<最初の実験の実験番号>, ?<0番目の実験の最大人数>)である。
  • dpという配列は一度しらべた関数の値を記憶しておくために使っている。
  • 条件を満たす最大の実験数しか教えてくれない(そのときにどんな割当になっているかを教えてくれない)ので役に立たない。

また、テストケースも1つしかやってないので間違っている可能性が高い。つまりは上のような手法があるよ、ということを伝えたかっただけ。

#include <vector>
#include <queue>
#include <iostream>

using namespace std;

#define Fill(a, b) memset(a, b, sizeof(a))


typedef vector<int> vi;
typedef vector<string> vs;

class MatchExperiments {
public:
  vector <vector <bool> > mc;
  vi ec;
  vi em;
  int memN;
  int expN;
  int dp[1<<10][20][10];
  int recur(int mask, int expNum, int curCap) {
    int tmpmax = 0;
    if (dp[mask][expNum][curCap] != -1) {
      return dp[mask][expNum][curCap];
    }
    if (expNum >= expN) {
      return 0;
    }
    if (curCap < 1) {
      // 実験[expNum]が人でいっぱいになったとき. 最小限の人数は確保されている
      return 1 + recur(mask, expNum+1, ec[expNum+1]);
    }

    // 現在の実験に人をさらに割り当てるとき
    for (int i=0; i<memN; i++) {
      if ((mask&(1<<i)) == 0 && mc[i][expNum]) {
	// 実験に割り当てられていないi番目の人を実験[expNum]に割り当ててみる
	tmpmax = max(tmpmax, recur(mask|(1<<i), expNum, curCap-1));
      }
    }

    // 現在の実験に人を割り当てるのをやめて、次の実験に進んだ場合
    if (em[expNum] <= ec[expNum] - curCap) {
      // 次の実験に移る際に、実験[expNum]が最小限の人数を確保しているとき
      tmpmax = max(tmpmax, 1 + recur(mask, expNum+1, ec[expNum+1]));
    } else {
      // 次の実験に移るけど、最小限の人数を確保しいていないとき
      tmpmax = max(tmpmax, recur(mask, expNum+1, ec[expNum+1]));
    }
    dp[mask][expNum][curCap] = tmpmax;
    return tmpmax;
  }  
  int mostExperiments(vector <vector <bool> > memberConditions,
		      vector <int> expCapacities,
		      vector <int> expMinCapacities){
    mc = memberConditions;
    ec = expCapacities;
    em = expMinCapacities;
    memN = mc.size();
    expN = ec.size();
    Fill(dp, -1);
    return recur(0, 0, ec[0]);
  }

private:
  void verify_case(int Case, const int &Expected, const int &Received) {
    cerr << "Test Case #" << Case << "...";
    if (Expected == Received) cerr << "PASSED" << endl;
    else {
      cerr << "FAILED" << endl;
      cerr << "\tExpected: \"" << Expected << '\"' << endl;
      cerr << "\tReceived: \"" << Received << '\"' << endl;
    }
  }
  void test_case_0() {
    // Boolean of who accept which experiment
    vector<vector <bool> > Arg0(4);
    vector <bool> t0(4);
    t0[0] = true; t0[1] = false; t0[2] = true; t0[3] = true;
    Arg0[0] = t0;

    vector <bool> t1(4);
    t1[0] = true; t1[1] = true; t1[2] = true; t1[3] = true;
    Arg0[1] = t1;

    vector <bool> t2(4);
    t2[0] = false; t2[1] = false; t2[2] = true; t2[3] = true;
    Arg0[2] = t2;

    vector <bool> t3(4);
    t3[0] = true; t3[1] = true; t3[2] = true; t3[3] = false;
    Arg0[3] = t3;

    // Capacities
    vector<int> Arg1(4);
    Arg1[0] = 1; Arg1[1] = 2; Arg1[2] = 4; Arg1[3] = 2;

    // Minimum Capacities
    vector<int> Arg2(4); // Minimam capacities
    Arg2[0] = 1; Arg2[1] = 1; Arg2[2] = 3; Arg2[3] = 2;
    int Arg3 = 3;
    verify_case(0, Arg3, mostExperiments(Arg0, Arg1, Arg2)); 
  }

public:
  void run_test(int Case) {
    if ((Case == -1) || (Case == 0)) test_case_0();
  }
};

int main() {
  MatchExperiments ___test;

  ___test.run_test(0);
  
}

テストvector <vector <bool> >の定義、もっといい方法ないのかなぁ。

vector <vector <bool> > Arg0 = {{false, false, true}, {true, false, true}, {false, true, false}};

みたいにやりたい。


ちなみにこの解放はTopCoder SRM397Div.2 1000の問題の解法を参考にしてみました。

また、「参加できる実験が少ない人を、割当人数下限の一番少ない実験に割り当てていく」というid:Mishoのシンプルな解法があるので、id:MIshoがそれを書いてくれると思います。

*1:これはJava用の問題

LiosKLiosK2008/04/21 23:55おーーーーーー

さすが!

diouf21diouf212008/04/22 11:28なぜ話を振ってきたんだぁ><。
でも、やりたい!!!!!!

卒研テーマ決定が終わって学内の発表が終わったらやってみよぉ

HashHash2008/04/22 19:31レベル高すぐる><
でも初級者のウチからトップレベルを見るのは大切かもしれん

 |