Hatena::Grouptopcoder

cou929のTopCoder日記

2009-11-03

SRM207 div2 (過去問)

10:17

Easy - TransportCounting

車に乗っていて、直線しかない道路を走っている。道路には何台かバスがいて、全てのバスは自分の車と同じ進行方向。自分の車の初期位置は0で、スピードが与えられる。また各バスの初期位置とスピードが与えられる。time時間経過後に、車は何台のバスを見たか。

時刻を一つ一つ増加させながら、どのバスと出会ったかをカウントするアプローチです。

class TransportCounting {
public:
  int countBuses(int speed, vector <int> positions, vector <int> velocities, int time)
  {
    int ret = 0;
    bool meeted[positions.size()];
    memset(meeted, false, sizeof(meeted));
    int pos = 0;

    for (int i=0; i<positions.size(); i++)
      if (positions[i] <= pos && !meeted[i])
	{
	  ret++;
	  meeted[i] = true;
	}

    for (int i=0; i<time; i++)
      {
	pos += speed;
	for (int j=0; j<positions.size(); j++)
	  {
	    positions[j] += velocities[j];
	    if (positions[j] <= pos && !meeted[j])
	      {
		ret++;
		meeted[j] = true;
	      }
	  }
      }

    return ret;
  }
};

Medium - RegularSeason

バスケットボールのトーナメントで、各チームの勝率と、各ラウンドの試合数が与えられる。チームを勝率順にソートして返す。

問題文の細かい部分がよくわからなかったんですが、exampleをみながらなんとか解きました。まず勝率の計算方法ですが、方法さえわかってしまえば簡単で、各チームの組み合わせごとに、ホームでの勝率*round + アウェイ(英語ではvisitorっていうんですね)での勝率 * roundを計算し、最後に全対戦カードぶん総和するだけです。丸め誤差をさけるために、分子だけを計算し、最後の結果を作る処理で100で割ります。このこともわざわざ問題文に書いてくれていました。次にソートする部分ですが、名前(string)とスコア(double)をそれぞれ昇順、降順にしなければいけないので、単にpairを使ってもできません。そこで構造体と比較のための叙述関数でソートします。最後に四捨五入は、0.5を足して小数点以下を切り捨て(intへキャスト)という常套手段を使いました。個人的には問題文の読解力とソートの仕方がポイントの問題でした。

typedef struct team
{
  string name;
  double score;
};

bool cmp(team a, team b)
{
  if (a.score == b.score)
    return a.name < b.name;
  else
    return a.score > b.score;
}

vector <string> splits(const string _s, const string del)
{
  vector <string> ret;
  string s = _s;

  while (!s.empty())
    {
      size_t pos = s.find(del);
      string sub = "";
      sub = s.substr(0, pos);
      ret.push_back(sub);
      if (pos != string::npos)
	pos += del.size();
      s.erase(0, pos);
    }

  return ret;
}

int toInt(string s) {int r = 0; istringstream ss(s); ss >> r; return r;}
string toStr(int n) {ostringstream ss; ss << n; return ss.str();}

class RegularSeason {
public:
  vector <string> finalStandings(vector <string> teams, int rounds)
  {
    vector <team> t;
    vector <vector <string> > steams;
    vector <string> ret;

    for (int i=0; i<teams.size(); i++)
      {
	vector <string> s = splits(teams[i], " ");
	team tt;
	tt.name = s[0];
	tt.score = 0;
	s.erase(s.begin());
	t.push_back(tt);
	steams.push_back(s);
      }

    for (int i=0; i<steams.size(); i++)
      for (int j=0; j<steams[i].size(); j++)
	if (i != j)
	  {
	    t[i].score += toInt(steams[i][j]) * rounds;
	    t[i].score += (100 - toInt(steams[j][i])) * rounds;
	  }

    sort(t.begin(), t.end(), cmp);

    for (int i=0; i<t.size(); i++)
      {
	string s;
	s = t[i].name;
	s += " ";
	double d = t[i].score / 100.0;
	d += 0.5;
	s += toStr((int)d);
	ret.push_back(s);
      }

    return ret;
  }
};

Hard - CaptureThemAll

チェスをプレイしていて、手駒はナイトのみ、相手はルークとクイーンを持っている。特別な魔法"ヘイスト"を使ったので、ナイトは何度でも動けるようになった。ナイトがルークとクイーンの両方をとる、最短ステップを求める。

BFSで解きました。はじめ、単純に全ての空間から探索していたので、ステップ数が大きくなると時間がかかって終わらずシステムテストに落ちました。例えば返り値が10ステップのケースだと、概算で8^10=1,073,741,824通りとなり、多すぎます。(余談ですが、テストでTLEで落ちるかなと思ったんですが、uncought exceptionという例外で落ちました。原因はよくわからないです。)

そこで、"ナイト-ルーク間の最小ステップ"、"ナイト-クイーン間の最小ステップ"、"ルーク-クイーン間の最小ステップ"をそれぞれ別に求め、最後に最小値を返す方法にしました。これで計算量が削減でき、システムテストも通りました。

typedef struct path
{
  int step;
  string pos;
};

class CaptureThemAll {
public:
  bool inRange(string pos)
  {
    if ('a' <= pos[0] && pos[0] <= 'h' && '1' <= pos[1] && pos[1] <= '8')
      return true;
    return false;
  }

  int r(string start, string goal)
  {
    int ret = 0;
    int rdir[8] = {-2, -2, -1, 1, 2, 2, -1, 1};
    int cdir[8] = {-1, 1, 2, 2, -1, 1, -2, -2};
    queue <path> q;
    path s;

    s.step = 0;
    s.pos = start;
    q.push(s);

    while (!q.empty())
      {
	path current = q.front();
	q.pop();

	if (current.pos == goal)
	  {
	    ret = current.step;
	    break;
	  }

	for (int i=0; i<8; i++)
	  {
	    char r = current.pos[0] + rdir[i];
	    char c = current.pos[1] + cdir[i];
	    string s;
	    s = r;
	    s += c;
	    if (inRange(s))
	      {
		path tmp;
		tmp.step = current.step + 1;
		tmp.pos = s;
		q.push(tmp);
	      }
	  }
      }

    return ret;
  }

  int fastKnight(string knight, string rook, string queen)
  {
    int k2r = 0, k2q = 0, r2q = 0;
    k2r = r(knight, rook);
    k2q = r(knight, queen);
    r2q = r(rook, queen);

    return min(k2r + r2q, k2q + r2q);
  }
};