[Bzoj3206][Apio2013]道路费用(kruscal)(缩点)
2018-04-11 17:20
651 查看
3206: [Apio2013]道路费用
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 536 Solved: 252
[Submit][Status][Discuss]
Description
Input
第一行包含三个由空格隔开的整数N,M和K。 接下来的 M行描述最开始的M 条道路 这M行中的第i行包含由空格隔开的整数ai,bi和c i,表示有一条在a i和b i之间,费用为c i的双向道路。 接下来的K行描述新建的K条道路。 这 K行中的第i行包含由空格隔开的整数 xi和yi,表示有一条连接城镇xi和yi新道路 最后一行包含N个由空格隔开的整数,其中的第j个为pj,表示从城镇j 前往城镇 1的人数。 输入也满足以下约束条件。 1 ≤ N ≤ 100000;1 ≤ K ≤ 20;1 ≤ M ≤ 300000;对每个i和j,1 ≤ ci, pj ≤ 10^6; 注意:边权值可能相同
Output
你的程序必须输出恰好一个整数到标准输出,表示能获得的最大的收入。
Sample Input
5 5 1 3 5 2 1 2 3 2 3 5 2 4 4 4 3 6 1 3 10 20 30 40 50
Sample Output
400
HINT
在样例中, Mr. Greedy应该将新道路(1,3)的费用设置为 5分钱。
在这个费用下,他可以选择道路(3,5),(1,2),(2,4)和(1,3)来最小化总费用,这个费用为14。
从城镇 3出发的 30个人和从城镇 5出发的 50个人将经过新道路前往城镇 1,因此他可以获得为(30+50)_5=400 分钱的最好收入。
如果我们这样做,将新道路(1,3)的费用设置为 10分钱。
根据传统的限制,Mr. Greedy必须选择(3,5),(1,2),(2,4)和(2,3),因为这是唯一费用最小的集合
。因此,在嘉年华的过程中道路(1,3)将没有任何收入。
Source
分析:
一开始有K条特殊边。我们可以二进制枚举哪些选哪些不选。
先把这K条特殊边权值赋-inf跑最小生成树,除了k条边以外其他边肯定在任何枚举中都会选。
那么把那些边缩点,最后剩下k个点。
我们再找出这k个点中可能选的边,最多k^2条。
这样二进制枚举加每次做最小生成树代价是2^k *(k ^ 2)
再dfs一编新树,把没有选的边u - v的路径上所以点暴力取最小值,这样每个点取得最小值记录为mx[i]。
每个点子树内权值和记录为w[i]
记录每个特殊边深度深的点为x
最终答案为∑mx[x] * w[x]。
AC代码:
# include <iostream> # include <cstdio> # include <cstring> # include <algorithm> using namespace std; typedef long long LL; const int N = 1e5 + 12; const int M = 4e5 + 12; const LL inf = 1e18; int n,m,K,dt,bac ,base ,cnt,tot,fa ; LL s ,S ,mx ,w ,ans;int head ,dep ,rt; struct Base{ int fa ; void init(int x){for(int i = 1;i <= x;i++)fa[i] = i;} int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);} }p,q; struct E{ int u,v;LL w; void read(bool f){scanf("%d %d",&u,&v);if(f)scanf("%lld",&w);} }a[M],b[52],e[252]; struct Edge{ int to,nex; }edge ; void AddEdge(int u,int v) { edge[++tot] = (Edge){v,head[u]}; head[u] = tot; edge[++tot] = (Edge){u,head[v]}; head[v] = tot; } bool cmp(E a,E b){return a.w < b.w;} void dfs(int u) { w[u] = s[u]; for(int i = head[u];i;i = edge[i].nex) { if(edge[i].to == fa[u])continue; fa[edge[i].to] = u; dep[edge[i].to] = dep[u] + 1; dfs(edge[i].to); w[u] += w[edge[i].to]; } } void solve(int sa) { tot = 0; for(int i = 1;i <= dt;i++) { mx[base[i]] = inf;fa[base[i]] = head[base[i]] = 0; p.fa[base[i]] = base[i]; } for(int i = 0;i < K;i++)if(sa >> i & 1) { int x = p.find(b[i].u),y = p.find(b[i].v); if(x == y)return; p.fa[y] = x;AddEdge(b[i].u,b[i].v); } for(int i = 0;i < cnt;i++) { int x = p.find(e[i].u),y = p.find(e[i].v); if(x != y)p.fa[y] = x,AddEdge(e[i].u,e[i].v); } dfs(rt); for(int i = 0;i < cnt;i++) { int x = e[i].u,y = e[i].v; if(dep[x] < dep[y])swap(x,y); while(dep[x] != dep[y]) { mx[x] = min(mx[x],e[i].w); x = fa[x]; } while(x != y) { mx[x] = min(mx[x],e[i].w); mx[y] = min(mx[y],e[i].w); x = fa[x];y = fa[y]; } } LL ret = 0; for(int i = 0;i < K;i++)if(sa >> i & 1) { int x = b[i].u,y = b[i].v; if(dep[x] < dep[y])swap(x,y); ret += mx[x] * w[x]; } ans = max(ans,ret); } int main() { freopen("TOLL.in","r",stdin); freopen("TOLL.out","w",stdout); scanf("%d %d %d",&n,&m,&K); p.init(n);q.init(n); for(int i = 0;i < m;i++)a[i].read(1); for(int i = 0;i < K;i++)b[i].read(0); for(int i = 1;i <= n;i++)scanf("%lld",S + i); sort(a,a + m,cmp); for(int i = 0;i < K;i++) { int x = p.find(b[i].u),y = p.find(b[i].v); if(x != y)p.fa[y] = x; } for(int i = 0;i < m;i++) { int x = p.find(a[i].u),y = p.find(a[i].v); if(x != y) { p.fa[y] = x; x = q.find(a[i].u),y = q.find(a[i].v); q.fa[y] = x; } } for(int i = 1;i <= n;i++)if(q.find(i) == i)base[++dt] = i,bac[i] = i; for(int i = 1;i <= n;i++)bac[i] = bac[q.find(i)],s[bac[i]] += S[i]; rt = bac[1]; for(int i = 0;i < m;i++)a[i].u = bac[a[i].u],a[i].v = bac[a[i].v]; for(int i = 0;i < K;i++)b[i].u = bac[b[i].u],b[i].v = bac[b[i].v]; for(int i = 0;i < m;i++) { int x = q.find(a[i].u),y = q.find(a[i].v); if(x != y) { q.fa[y] = x; e[cnt++] = a[i]; } } int all = 1 << K; for(int i = 1;i < all;i++)solve(i); printf("%lld\n",ans); fclose(stdin); fclose(stdout); return 0; }
相关文章推荐
- bzoj 3206: [Apio2013]道路费用【最小生成树+并查集】
- [BZOJ3206][APIO2013]道路费用(最小生成树)
- BZOJ3206 [Apio2013]道路费用
- bzoj 3206: [Apio2013]道路费用 dfs+最小生成树+并查集
- bzoj3206 [Apio2013]道路费用
- bzoj3206 [Apio2013]道路费用
- bzoj 3206: [Apio2013]道路费用 最小生成树
- bzoj 3206: [Apio2013]道路费用
- NKOJ 2784 (APIO 2013) 道路费用(最小生成树+缩点)
- 3206: [Apio2013]道路费用
- 【C++心路历程30】(APIO2013)道路费用
- bzoj3206 [Apio2013]道路费用(kruskal+并查集+状压枚举+dfs)
- BZOJ3206: [Apio2013]道路费用
- BZOJ 3205 [Apio2013]机器人 ——斯坦纳树
- 【BZOJ】【P2893】【征服王】【题解】【缩点费用流】
- [bzoj3130][sdoi2013]费用流
- BZOJ 3130 [Sdoi2013]费用流 题解
- 【bzoj3624】【apio2008】免费道路
- BZOJ 3171 TJOI 2013 循环格 费用流
- 【SDOI2013】【BZOJ3130】费用流