第四节 状压 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
题目等价于建立若干环。

浙公网安备 33010602011771号