euphonictechnologies’s diary

Haskell超初心者の日記です。OCamlが好きです。

follow us in feedly

TopCoder SRM 667 Div1 Easy : OrderOfOperations

全然解けなかった。朝起きてもう一回やってみたら解けた。おそらく寝てる間に頑張ったのかな。

方針

bitDPを使う。全ビットのOR和がゴール状態なのでdp[ <ゴール状態> ]が答え。例えば

  • 1110
  • 0100
  • 0010

ならdp[ "0b1110" ] が答え。

更新方法はstateから遷移できるすべてのパターンに対して(つまり以下のnextは与えられたインストラクションのすべての中の一つ)

  • dp[stateをnextした後] = min(dp[stateをnextした後], dp[state] + dist( state, next ))

で更新していく。 stateをnextするのは単にOR和。OR和の中にすでに訪れたstateに関する情報が含まれているので、あるstateに達するための経路を保持する必要はない。 すべてのstateを通り抜けないと最終stateに達しないので(これは不正確、だけど雰囲気は伝わるか)、単に経路のことは忘れてすべての取りうるstateに関してdp[goal]を求めればよい。

m(各インストラクション内の最大ビット数)が高々20までなので、forで回せばよい。

Code

public class OrderOfOperations {

    private int popcount(int a) {
        int c = a;
        int ans = 0;
        for (int i = 0; i < 32; ++i) {
            ans += (c & 1) > 0 ? 1 : 0;
            c = c >> 1;
        }
        return ans;
    }

    private int dist(int a, int b) {
        int c = (a ^ b) & (~a);
        int ans = popcount(c);
        ans = (ans < 0) ? 0 : ans;
//        System.out.println(Integer.toBinaryString(a) + "->" + Integer.toBinaryString(b) + "=" + ans + " bits");
        return ans * ans;
    }

    public int minTime(String[] s) {
        int ninst = s.length;
        int nmem = s[0].length();
        int[] ss = new int[ninst];
        int goal = 0;
        for (int i = 0; i < ninst; ++i) {
            ss[i] = Integer.parseInt(s[i], 2);
            goal = goal | ss[i];
        }

        int dp[] = new int[(1 << 22)];
        int inf = 99999999;
        for (int j = 0; j < (1 << nmem); ++j) dp[j] = inf;
        dp[0] = 0;

        for (int i = 0; i < (1 << nmem); ++i) {
            for (int e : ss) {
                if(dp[i] == inf) continue;
                int d = dist(i, e);
                dp[i | e] = (dp[i | e] < dp[i] + d) ? dp[i | e] : dp[i] + d;
            }
        }

        return dp[goal];
    }
}

反省

  • 時間内に解けなかった。なぜかグラフにして最短路を求めようとしてしまった。死にたい。
  • 上のpopcountはださい。時間なかったから…。
  • div2でもう一回頑張ります。