LightOJ 1057金の収集(選圧DP)

トピック

N * M N M < 20 20 グリッド上に人がいて、15個以下の金鉱があります。この人が現在の場所からすべての金鉱を取得してからこの場所に戻るのにどのくらい時間がかかりますか?一度に4つの隣接する方向にのみ行くことができます。

アイデア

障害物がないので、2つのグリッド間の距離を計算するのは非常に便利です。
最初は金鉱石を取得するすべての順序が使い果たされ、次にTLEが実行され、
最後に圧倒され、dp [sta] [i]は、i番目の金鉱山の州立駅の最小距離に到達することを意味します。

char mp[22][22];
int dp[(1 << 16) + 1][16];
int dis(ii a, ii b) {
    return max(abs(a.first - b.first) , abs(a.second - b.second));
}
int main(int argc, const char * argv[])
{
    int kase;cin >> kase;
    while(kase--) {
        int n, m;scanf("%d%d", &n, &m);
        Rep(i, 1, n) scanf("%s", mp[i] + 1);
        ii st;
        vector<ii> v;
        Rep(i, 1, n) {
            Rep(j, 1, m) {
                if (mp[i][j] == 'x') st = ii(i, j);
                if (mp[i][j] == 'g') v.push_back(ii(i, j));
            }
        }
        memset(dp, inf, sizeof dp);
        int Size = (int)v.size();
        for (int i = 0;i < Size;++i)
            dp[1 << i][i] = dis(st, v[i]);
        for (int sta = 1;sta < 1 << Size;++sta) {
            for (int i = 0;i < Size;++i) {
                if ((sta & (1 << i)) && dp[sta][i] != inf) {
                    for (int j = 0;j < Size;++j) {
                        if ((sta & (1 << j)) == 0) {
                            //i -> j
                            dp[sta | (1 << j)][j] = min(dp[sta | (1 << j)][j], dp[sta][i] + dis(v[i], v[j]));
                        }
                    }
                }
            }
        }
        int ans = inf;
        for (int i = 0;i < Size;++i)
            ans = min(ans, dp[(1 << Size) - 1][i] + dis(v[i], st));
        if (Size == 0) ans = 0;
        printf("Case %d: %d\n", ++nCase, ans);
    }

    // showtime;
    return 0;
}

おすすめ

転載: blog.csdn.net/KIJamesQi/article/details/55099976