【状压DP】吃货JYY(luogu 6085)
生活随笔
收集整理的這篇文章主要介紹了
【状压DP】吃货JYY(luogu 6085)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
正題
luogu 6085
題目大意
給你一個無向圖,其中有一些邊是必須走的,問你從1開始走,經(jīng)過所有必須走的邊,然后回到1的最短路徑
解題思路
n很小,可以先用Floyd跑出兩個點(diǎn)之間的最短路
然后狀壓DP,每個點(diǎn)存三種狀態(tài):
0.不在連通圖內(nèi)
1.在連通圖內(nèi)且連邊為奇數(shù)
2.在連通圖內(nèi)且連邊為偶數(shù)
遍歷所有狀態(tài),每個狀態(tài)找不在連通圖內(nèi)的點(diǎn),然后和連通圖內(nèi)一點(diǎn)連邊,然后記錄奇偶性(必要的邊不記錄)
枚舉完所有狀態(tài)后,把必要的邊加進(jìn)里面,然后對于連邊為奇數(shù)的,找到一種最小代價連接方式,這樣可以構(gòu)造一條回路
代碼
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 1594323 using namespace std; int n, m, k, x, y, z, p, MX, nec, sum, ans, tot, h[100], v[100], g[10000], deg[100], dis[100][100]; int f[N + 10]; queue<int>d; struct rec {int to, l, next; }e[200]; void add(int x, int y, int z) {e[++tot].to = y;e[tot].l = z;e[tot].next = h[x];h[x] = tot; } int main() {memset(dis, 127/3, sizeof(dis));memset(g, 127/3, sizeof(g));memset(f, 127/3, sizeof(f));MX = g[0];scanf("%d%d", &n, &m);for (int i = 1; i <= m; ++i){scanf("%d%d%d", &x, &y, &z);x--;y--;add(x, y, z);add(y, x, z);dis[x][y] = dis[y][x] = min(dis[x][y], z);nec ^= (1<<x) ^ (1<<y);deg[x]++;deg[y]++;sum += z;}scanf("%d", &m);for (int i = 1; i <= m; ++i){scanf("%d%d%d", &x, &y, &z);x--;y--;dis[x][y] = dis[y][x] = min(dis[x][y], z);}v[0] = 1;dis[0][0] = 0;for (int i = 1; i <= n; ++i)v[i] = v[i - 1] * 3, dis[i][i] = 0;for (int k = 0; k < n; ++k)for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j)dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);//Floydg[0] = 0;for (int now = 0; now < (1<<n); ++now)for (int i = 0; i < n; ++i)if (!(now & (1<<i)))for (int j = i + 1; j < n; ++j)if (!(now & (1<<j))){k = now ^ (1<<i) ^ (1<<j);g[k] = min(g[k], g[now] + dis[i][j]);//預(yù)處理奇數(shù)點(diǎn)的連邊}d.push(2);f[2] = 0;while(!d.empty()){int now = d.front();d.pop();for (int i = 0; i < n; ++i){if (now / v[i] % 3) continue;k = now + v[i] * 2;//必須的連邊不算奇偶性for (int j = h[i]; j; j = e[j].next){if (!(now / v[e[j].to] % 3)) continue;if (f[k] >= MX) d.push(k);f[k] = min(f[k], f[now]);}for (int j = 0; j < n; ++j)//不必須的連邊{if (!(now / v[j] % 3)) continue;k = now + v[i];if (now / v[j] % 3 == 2) k -= v[j];//計算奇偶性else k += v[j];if (f[k] >= MX) d.push(k);f[k] = min(f[k], f[now] + dis[j][i]);}}}ans = MX;for (int now = 0; now <= v[n]; ++now){p = 0;k = 0;for (int i = 0; i < n; ++i){if (!(now / v[i] % 3) && deg[i])//有必須的點(diǎn)不在連通圖內(nèi){p = 1;break;}if (now / v[i] % 3) k ^= (1<<i) * (now / v[i] % 3 == 1? 1: 0);//計算奇偶性}if (p) continue;k ^= nec;ans = min(ans, f[now] + g[k]);}printf("%d", sum + ans);return 0; }總結(jié)
以上是生活随笔為你收集整理的【状压DP】吃货JYY(luogu 6085)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不想装截图工具不想装截图工具了
- 下一篇: 纪中A组模拟赛总结(2021.7.21)