BZOJ4006: [JLOI2015]管道连接(斯坦纳树,状压DP)
2018-06-17 20:42:54来源:未知 阅读 ()
Submit: 1171 Solved: 639
[Submit][Status][Discuss]
Description
小铭铭最近进入了某情报部门,该部门正在被如何建立安全的通道连接困扰。
Input
第一行包含三个整数 n;m;p,表示情报站的数量,可以建立的通道数量和重要情报站的数
Output
输出一行一个整数,表示任意相同频道的情报站之间都建立通道连接所花费的最少资源总量。
Sample Input
1 2 3
1 3 2
1 5 1
2 4 2
2 5 1
3 4 3
3 5 1
4 5 1
1 1
1 2
2 3
2 4
Sample Output
HINT
选择 (1; 5); (3; 5); (2; 5); (4; 5) 这 4 对情报站连接。
Source
斯坦纳森林
设$f[i][sta]$表示$i$号节点,与关键节点的联通性为$sta$时的最小值
假设我们已经求出了$f$
那么我们令$g[sta]$表示,颜色联通性为$sta$时的最小值
$g$比较好求,枚举子集转移就可以
$f$的话,如果学过斯坦纳树也比较好求
按照套路,两种转移方法,一种是枚举子集,一种是SPFA
#include<cstdio> #include<queue> #include<cstring> using namespace std; const int MAXN = 1e6 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') {x = x * 10 + c - '0'; c = getchar();} return x * f; } int N, M, P; struct node { int u, v, w, nxt; }E[MAXN]; int head[MAXN], num = 1; inline void AddEdge(int x, int y,int z) { E[num].u = x; E[num].v = y; E[num].w = z; E[num].nxt = head[x]; head[x] = num++; } struct Point { int color, ID; }a[MAXN]; int f[1051][1051], g[1051]; int vis[MAXN], sum[MAXN]; queue<int>q; void SPFA(int now) { while(q.size() != 0) { int p = q.front(); q.pop(); vis[p] = 0; for(int i = head[p]; i != -1; i = E[i].nxt) { int v = E[i].v; if(f[v][now] > f[p][now] + E[i].w) { f[v][now] = f[p][now] + E[i].w; if(!vis[v]) vis[v] = 1, q.push(v); } } } } int tmp[11]; bool check(int sta) { memset(tmp, 0, sizeof(tmp)); for(int i = 1; i <= 10; i++) if(sta & (1 << i - 1)) tmp[a[i].color]++; for(int i = 1; i <= 10; i++) if(tmp[i] && tmp[i] != sum[i]) return 0; return 1; } int main() { #ifdef WIN32 freopen("a.in", "r", stdin); #endif memset(head, -1, sizeof(head)); N = read(), M = read(), P = read(); for(int i = 1; i <= M; i++) { int x = read(), y = read(), z = read(); AddEdge(x, y, z);AddEdge(y, x, z); } memset(f, 0x3f, sizeof(f)); memset(g, 0x3f, sizeof(g)); for(int i = 1; i <= P; i++) a[i].color = read(), a[i].ID = read(), sum[a[i].color]++,f[a[i].ID][1 << (i - 1)] = 0; int limit = (1 << P) - 1; for(int sta = 0; sta <= limit; sta++) { for(int i = 1; i <= N; i++) { for(int S = sta; S; S = (S - 1) & sta) f[i][sta] = min(f[i][sta], f[i][S] + f[i][sta - S]); q.push(i),vis[i] = 1; } SPFA(sta); } for(int sta = 0; sta <= limit; sta++) for(int i = 1; i <= N; i++) g[sta] = min(g[sta], f[i][sta]); for(int sta = 0; sta <= limit; sta++) if(check(sta)) for(int S = sta; S; S = (S - 1) & sta) if(check(S)) g[sta] = min(g[sta], g[S] + g[sta - S]); printf("%d", g[(1 << P) - 1]); return 0; }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- C++ 进程和匿名管道使用学习 2020-01-14
- 匿名管道通讯实现 2019-02-20
- Linux进程间通信 --- 管道 2018-06-18
- Windows进程间通信—命名管道 2018-06-18
- Vijos / 题库 / 输油管道问题 2018-06-17
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash