BZOJ 3590 [双连通分量][状压DP]
来源:互联网 发布:qq国际版for ubuntu 编辑:程序博客网 时间:2024/05/18 02:04
Description
求一个包含所有节点的边双联通分量,并是边权和最小。
Solution
注意到任意的一个边双连通分量都是由一条链和一个子双连通分量构成的,而且题中节点数
令
令
令
则可以通过
#include <cstring>#include <iostream>using namespace std;inline char get(void) { static char buf[100000], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, 100000, stdin); if (S == T) return EOF; } return *S++;}inline void read(int &x) { static char c; x = 0; for (c = get(); c < '0' || c > '9'; c = get()); for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';}const int INF = 0x1f1f1f1f;const int M = 15;const int N = (1 << 12) + 10;int test, n, m, x, y, z, Sn, mn, se, Gcnt;int id[M], head[M];int f[N], h[N][M][2], g[N][M][M];struct edge { int to, next, key; edge(int t = 0, int n = 0, int k = 0):to(t), next(n), key(k) {}};edge G[M * M * 2];inline int Min(int a, int b) { return a < b ? a : b;}inline void AddEdge(int from, int to, int key) { G[++Gcnt] = edge(to, head[from], key); head[from] = Gcnt; G[++Gcnt] = edge(from, head[to], key); head[to] = Gcnt;}int main(void) { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); read(test); for (int i = 0; i < 12; i++) id[i + 1] = 1 << i; while (test--) { memset(f, 0x1f, sizeof f); memset(g, 0x1f, sizeof g); Gcnt = 0; memset(head, 0, sizeof head); read(n); read(m); Sn = 1 << n; for (int i = 1; i <= m; i++) { read(x); read(y); read(z); AddEdge(x, y, z); } for (int i = 1; i <= n; i++) f[id[i]] = g[id[i]][i][i] = 0; for (int S = 0; S < Sn; S++) { for (int i = 1; i <= n; i++) { mn = INF; se = INF; for (int j = head[i]; j; j = G[j].next) { if (id[G[j].to] & S) { if (G[j].key <= mn) { se = mn; mn = G[j].key; } else if (G[j].key < se){ se = G[j].key; } } } h[S][i][0] = mn; h[S][i][1] = se; } } for (int S = 1; S < Sn; S++) for (int i = 1; i <= n; i++) if (id[i] & S) for (int j = 1; j <= n; j++) if (id[j] & S) { for (int p = head[i]; p; p = G[p].next) if(!(id[G[p].to] & S)) g[S | id[G[p].to]][G[p].to][j] = Min(g[S | id[G[p].to]][G[p].to][j], g[S][i][j] + G[p].key); for (int p = head[j]; p; p = G[p].next) if(!(id[G[p].to] & S)) g[S | id[G[p].to]][i][G[p].to] = Min(g[S | id[G[p].to]][i][G[p].to], g[S][i][j] + G[p].key); } for (int S = 1; S < Sn; S++) { int R = (Sn - 1) ^ S; for (int T = R; T; T = (T - 1) & R) { for (int i = 1; i <= n; i++) if (id[i] & T) for (int j = 1; j <= n; j++) if (id[j] & T) if (i == j) f[S | T] = Min(f[S | T], f[S] + h[S][i][0] + h[S][j][1] + g[T][i][j]); else f[S | T] = Min(f[S | T], f[S] + h[S][i][0] + h[S][j][0] + g[T][i][j]); } } if (f[Sn - 1] >= INF) puts("impossible"); else printf("%d\n", f[Sn - 1]); } return 0;}
阅读全文
2 0
- BZOJ 3590 [双连通分量][状压DP]
- [状压DP 边双连通分量] BZOJ 3590 [Snoi2013]Quare
- BZOJ 3590 Quare [状压DP][边双连通分量][点双联通分量]
- 【BZOJ3590】[Snoi2013]Quare【双连通分量】【状压DP】【神题】
- BZOJ 4435 [双连通分量][Hash]
- [双连通分量][DP]免费航班
- 双连通分量
- 双连通分量_road
- 边双连通分量
- 双连通分量
- 双连通分量-tarjan
- 双连通分量
- 双连通分量
- 双连通分量-tarjan
- 双连通分量
- poj3177 双连通分量
- 点双连通分量
- 双连通分量
- MFC View类对话框类之间指针的相互获取
- method swizzling使用一例
- java捕获到异常以后,后面的代码还会执行吗?
- NYOJ 448 寻找最大数
- Fox And Two Dots --DFS
- BZOJ 3590 [双连通分量][状压DP]
- YARN 服务库与事件库
- 经典AOP
- 2017.07.31回顾 LabelEncoder xgb.cv
- 数组
- 常用但没记住命令
- 高效学习之模型分析
- 51Nod-1619-完全二叉树的方差
- Java 从控制台读入一个动态字符串数组