[BZOJ3206][APIO2013]道路费用(最小生成树)
3206: [Apio2013]道路费用
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 568 Solved: 266
[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 50Sample Output
400HINT
在样例中, 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
这种题一般不是数据结构+分类讨论,就是缩图。
1.首先把K条边全部选上,这个时候图可能仍然不连通,于是将M条原边排序,从小到大加入直到图连通。根据M条边权值互不相同可以知道,加进来的这些原边是任意一个方案都必须有的。我们将原边构成的连通块缩成点,显然图最多只有K+1个点。
2.为了保证后面枚举的复杂度,我们要找到能将K+1个点连通起来的最小的K条边,可以发现后面枚举只会使用这K条原边。
3.$O(2^K)$枚举K条边并加入图中(如果构成环则退出),剩下的将选出的K条原边从小到大加入,建出当前方案下的MST。
4.现在需要确定每条Mr. Greedy的边的权值,根据MST的圈性质可知,边<u,v>的权值肯定不能大于MST上u到v的路径中原边的最大值,依次暴力确定即可。
时间复杂度$O(m\alpha(m)+K^22^K)$,理论上可能并不能过。
#include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,M=,inf=;
int n,m,K,tot,tmp,cnt,rt,x,d[N],to[],nxt[],c[],f[N],h[N],fa[][N];
ll sz[N],val[N],ans;
struct E{ int x,y,z; bool operator <(const E &a)const{ return z<a.z; }; }a[M],b[];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
int get(int k,int x){ return (fa[k][x]==x) ? x : fa[k][x]=get(k,fa[k][x]); }
void uni(int k,int x,int y){ int u=get(k,x),v=get(k,y); if (u!=v) fa[k][u]=v; } void dfs(int x){
sz[x]=val[x];
for (int i=h[x],k; i; i=nxt[i])
if ((k=to[i])!=fa[][x])
fa[][k]=x,d[k]=d[x]+,dfs(k),sz[x]+=sz[k];
} int main(){
freopen("bzoj3206.in","r",stdin);
freopen("bzoj3206.out","w",stdout);
scanf("%d%d%d",&n,&m,&K);
rep(i,,m) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
sort(a+,a+m+);
rep(i,,n) fa[][i]=fa[][i]=i;
rep(i,,K) scanf("%d%d",&b[i].x,&b[i].y),uni(,b[i].x,b[i].y);
rep(i,,m){
int u=get(,a[i].x),v=get(,a[i].y);
if (u!=v) fa[][u]=v,uni(,a[i].x,a[i].y);
}
rt=get(,);
rep(i,,n) if (get(,i)==i) c[++tot]=i;
rep(i,,n) scanf("%d",&x),val[get(,i)]+=x;
rep(i,,m) a[i].x=get(,a[i].x),a[i].y=get(,a[i].y);
rep(i,,K) b[i].x=get(,b[i].x),b[i].y=get(,b[i].y);
rep(i,,m){
int u=get(,a[i].x),v=get(,a[i].y);
if (u!=v) a[++tmp]=a[i],fa[][u]=v;
}
for (int S=; S<<<K; S++){
bool flag=; cnt=;
rep(i,,tot) fa[][c[i]]=h[c[i]]=,f[c[i]]=inf,fa[][c[i]]=c[i];
rep(i,,K) if (S&(<<(i-))){
int u=get(,b[i].x),v=get(,b[i].y);
if (u==v) { flag=; break; } fa[][u]=v;
add(b[i].x,b[i].y); add(b[i].y,b[i].x);
}
if (flag) continue;
rep(i,,K){
int u=get(,a[i].x),v=get(,a[i].y);
if (u!=v) fa[][u]=v,add(a[i].x,a[i].y),add(a[i].y,a[i].x);
}
dfs(rt);
rep(i,,K){
int u=a[i].x,v=a[i].y;
if (d[u]<d[v]) swap(u,v);
for (; d[u]!=d[v]; u=fa[][u]) f[u]=min(f[u],a[i].z);
for (; u!=v; u=fa[][u],v=fa[][v]) f[u]=min(f[u],a[i].z),f[v]=min(f[v],a[i].z);
}
ll tmp=;
rep(i,,K) if (S&(<<(i-))){
int u=b[i].x,v=b[i].y;
if (d[u]<d[v]) swap(u,v);
tmp+=sz[u]*f[u];
}
ans=max(ans,tmp);
}
printf("%lld\n",ans);
return ;
}
[BZOJ3206][APIO2013]道路费用(最小生成树)的更多相关文章
- [Bzoj3206][Apio2013]道路费用(kruscal)(缩点)
3206: [Apio2013]道路费用 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 536 Solved: 252[Submit][Status ...
- BZOJ3206 [Apio2013]道路费用
首先我们强制要求几条待定价的边在MST中,建出MST 我们发现这个MST中原来的边是一定要被选上的,所以可以把点缩起来,搞成一棵只有$K$个点的树 然后$2^K$枚举每条边在不在最终的MST中,让在最 ...
- 洛谷P3639 [APIO2013] 道路费用 [生成树的特殊算法]
题目传送门 道路费用 格式难调,题面就不放了. 分析: 这是一道要细(yan)心(jing)的生成树的好(gui)题. 首先我们看到$k$的范围非常小,那么我们就可以直接$2^k$枚举每一条加边是否选 ...
- bzoj 3206: [Apio2013]道路费用【最小生成树+并查集】
参考:http://hzwer.com/6888.html 把k条道路权值设为0,和其他边一起跑MST,然后把此时选中的其他边设为必选,在新图中加上必选变缩成k个点,把所有边重标号,枚举k跳边的选取情 ...
- [APIO2013]道路费用
题目描述 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人从城镇 1 出发,经过这 ...
- 题解 [APIO2013]道路费用
link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...
- 题解 洛谷 P3639 【[APIO2013]道路费用 】
不难想到可以\(2^k\)去枚举\(k\)条新边的选择方案,然后加入原图中的边来使图连通,用当前方案的收益去更新答案,但是这样复杂度过不去. 可以先把\(k\)条新边都连上,然后再加入边权从小到大排序 ...
- bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路【最小生成树】
先把已有的边并查集了,然后MST即可 记得开double #include<iostream> #include<cstdio> #include<algorithm&g ...
- PKUSC2018训练日程(4.18~5.30)
(总计:共66题) 4.18~4.25:19题 4.26~5.2:17题 5.3~5.9: 6题 5.10~5.16: 6题 5.17~5.23: 9题 5.24~5.30: 9题 4.18 [BZO ...
随机推荐
- underscore的bind和bindAll方法
bind方法和bindAll方法都是用来设定函数的this值的,区别是调用方式不同. var xiaoming = { say:function(){ console.log('I am xiaomi ...
- 数据安全之MD5、SHA-1、CRC32区别
crc32 — 计算一个字符串的 crc32 多项式 生成 string 参数的 32 位循环冗余校验码多项式……:这句话从英文翻译过来的,不正确,准确的说应该是这么理解: 以32位循环冗余校验多项式 ...
- Linux 查看文件和文件夹大小
当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择. df可以查看一级文件夹大小.使用比例.档案系统及其挂入点,但对文件却无能为力. du可以查看文件及文件夹的大小. ...
- python3 yield表达式形式应用
我们已知: 生成器函数:函数体内包含有yield关键字,该函数执行的结果是生成器 yield的功能: 1.与return类似,都可以返回值,但不一样的地方在于yield返回多次值,而return只能返 ...
- UVA 10385 Duathlon
Problem HDuathlonInput: standard inputOutput: standard outputTime Limit: 15 seconds A duathlon is a ...
- JMeter 定时器(Synchronizing Timer)之集合点应用
性能测试中我们经常提到一个概念就是“并发”,其实在实际真实的性能测试中是不存在真正的并发的.为了更真实的模拟对一个请求的并发测试场景,我们通常设置一个集合点,JMeter中提供了这样的一个功能设置. ...
- 汉字hash问题(转)
一.汉字编码的种类 汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5. 1.GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆.新加坡等地也使用此编码.它 ...
- 使用MXNet远程编写卷积神经网络用于多标签分类
最近试试深度学习能做点什么事情.MXNet是一个与Tensorflow类似的开源深度学习框架,在GPU显存利用率上效率高,比起Tensorflow显著节约显存,并且天生支持分布式深度学习,单机多卡.多 ...
- bootstrap,ECMA
前端UI(布局)框架 bootstrap Amaze UI BootStrap 全局css样式 栅格系统 container 容器 超小屏幕 手机 vw <768px 宽度 100% 小屏幕 平 ...
- 如何生成pyc/pyo/pyd文件
# 一.如何生成pyc/pyo文件 # 1.通过编写代码生成 import py_compile # 参数如下 ''' def compile(file, cfile=None, dfile=None ...