mayoko’s diary

プロコンとかいろいろ。

AOJ 2306 Rabbit Party

問題

Rabbit Party | Aizu Online Judge

n 匹のウサギがパーティーをする。各ウサギには友達度が定義されている(これが正の値を取るのは高々 m 個)。
ウサギ i がパーティーに参加した際の満足度は, パーティーに参加したウサギのうち, 友達度が最も低いものとのそれに等しく, パーティー全体の満足度は, パーティーに参加したウサギの満足度の和である。これを最大化せよ。

解法

a, b の友達度が 0 の場合, 少なくとも a と b のどちらかはパーティーに参加しないほうが得です(a と b の満足度はどちらも 0 になるのでうまみがないし, ほかのウサギにとっても損はあっても得はない)。
つまり, パーティー全体の満足度を最大化する組み合わせにおいて,

  • 任意の (i, j) について, i と j の友達度は正

ということが成り立っているはずです。m は 100 と小さいので, これを満たす集合は, どんなに大きくても 14 にしかなりません。それを考えると, 上記の条件を満たす, ということだけ保つように dfs すれば十分高速に答えを求められそうな気がします。

試しに書いてみると, 通りました。

const int MAXN = 111;
const int INF = 1e9;
int mat[MAXN][MAXN];
int ans;
int n, m;

void dfs(vector<int>& v) {
    int sz = v.size();
    if (v.size() > 1) {
        int tmp = 0;
        for (int i = 0; i < sz; i++) {
            int mini = INF;
            for (int j = 0; j < sz; j++) if (j != i) {
                mini = min(mini, mat[v[i]][v[j]]);
            }
            tmp += mini;
        }
        ans = max(ans, tmp);
    }
    int last = v.back();
    for (int i = last+1; i < n; i++) {
        bool ok = true;
        for (int j = 0; j < sz; j++) {
            if (!mat[i][v[j]]) {
                ok = false;
                break;
            }
        }
        if (ok) {
            v.push_back(i);
            dfs(v);
            v.pop_back();
        }
    }
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < m; i++) {
        int u, v, f;
        cin >> u >> v >> f;
        u--; v--;
        mat[u][v] = mat[v][u] = f;
    }
    ans = 0;
    for (int i = 0; i < n; i++) {
        vector<int> v(1, i);
        dfs(v);
    }
    cout << ans << endl;
    return 0;
}