第四节 状压 dp (Ex. Hard Ver.!) (草稿版)

到底是谁一直在白嫖我的题解。

状压 dp 没啥简单题了,全被我做完了。

那只好上点难度了。Extra Hard Version!

非常珍贵的题目,要好好做啊。

[NOIP 2017 提高组] 宝藏

首先这么多边可以直接去重了,这个是毋庸置疑的。

然后起点肯定是需要枚举的,因为起点的位置不太确定的时候没法直接算。

固然可以以起点为根建立一棵树,同样的层数所花费的倍率是相同的。

然后考虑从一个状态转移到另一个状态与该状态的并集,其代价是完全可以预处理出来的。

本质上状态之间的转移是相邻不同层之间的。如果不相邻,则其一定不为最优决策。

其他的细节可以直接看代码了。

#include <bits/stdc++.h>
using namespace std;

const long long INF = 0x1111111111111111;
int n, m, e[15][15];
int f[1 << 12][1 << 12];
long long dp[15][1 << 12], ans = INF;

void init(){
    for (int x = 1; x < (1 << n); x++){
        for (int y = (x - 1) & x; y; y = (y - 1) & x){
            for (int i = 1; i <= n; i++){
                if (!((x ^ y) & (1 << i - 1))) continue;
                long long res = INF;
                for (int j = 1; j <= n; j++){
                    if (y & (1 << j - 1))
                        res = min(res, 1ll * e[i][j]);
                }
                if (res >= INF){ f[y][x] = INF; break; }
                else f[y][x] += res;
            }
        }
    }
}

long long cal(int s){
    memset(dp, 0x11, sizeof dp); dp[0][1 << s - 1] = 0;
    for (int i = 1; i < n; i++){
        for (int x = 1; x < (1 << n); x++){
            for (int y = (x - 1) & x; y; y = (y - 1) & x){
                dp[i][x] = min(dp[i][x], dp[i - 1][y] + 1ll * i * f[y][x]);
            }
        }
    }
    long long ret = INF;
    for (int i = 0; i < n; i++)
        ret = min(ret, dp[i][(1 << n) - 1]);
    return ret;
}

int main(){
    cin >> n >> m; memset(e, 0x11, sizeof e);
    for (int i = 1; i <= m; i++){
        int u, v, t; cin >> u >> v >> t;
        e[u][v] = e[v][u] = min(e[u][v], t);
    }
    init();
    for (int i = 1; i <= n; i++)
        ans = min(ans, cal(i));
    cout << ans << endl;
    return 0;
}

初始值不要开太大,不然容易炸掉 long long。

[USACO22FEB] Redistributing Gifts G

题目等价于建立若干环。

posted @ 2026-09-17 14:58  _lhr  阅读(3)  评论(0)    收藏  举报