[NOIP2015模拟10.22] 最小代价 解题报告 (最小生成树)
Description
其中有些点是黑点,其他点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个黑点,可以选取其中任意一个),我们想要使得花费的代价最小。请问这个最小代价是多少?
注意:最后选出的边保证每个白点到离它最近的黑点的距离仍然等于原图中的最短距离。
Input
第二行n个整数,0表示白点,1表示黑点;
接下来m行,每行三个整数x,y,z,表示一条连接x和y点,权值为z的边。
Output
否则,输出最小代价。
Sample Input
5 7
0 1 0 1 0
1 2 11
1 3 1
1 5 17
2 3 1
3 5 18
4 5 3
2 4 5
Sample Output
5
【样例解释】
选2、4、6三条边
Data Constraint
对100%的输入数据:1≤n≤100000,1≤m≤200000,1≤z≤1000000000
题目大意:给你一张图,点分成黑点和白点,在保证白点到离自己最近的黑点存在最短路的情况下花尽可能少的代价。
乍一看题目,好像不知所云。但是仔细研究发现,在没有对原图进行操作的情况下我们很难保证白点到离自己黑点的最短路还存在,于是乎,下面的解法就诞生了。
我们考虑添加超级点S,在S 与每个黑点间连权值为0的边,先处理从S 出发到每个点的最短距离,我们可以取出一张最短路径图,现在我们的问题就变成了取权值最小的边的集合 使得这幅图连接,那么,最小生成树算法就可以完美地解决这个问题。
怎么取出这个最短路径图?如下代码:
void get()
{
for (int i=;i<=n;i++)
{
if (a[i]) continue;
for (int j=head[i];j;j=edge[j].next)
{
int y=edge[j].to;
if (y==) continue;
if (dist[y]+1ll*edge[j].l==dist[i]) edge[j].fl=;
}
}
}
也就是说我们枚举每一个白点连的边,如果dist是通过这条边去更新的那么就fl赋值为1,表示它属于最短路径图。于是对fl为1的边跑最小生成树就好了。
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std; const int maxn=+;
int n,m,tot,S,cnt;
int a[maxn],head[maxn],vis[maxn],fa[maxn];
ll dist[maxn];
struct EDGE
{
int from;int to;int next;int l;int fl;
}edge[maxn<<];
inline int read()
{
char ch=getchar();
int s=,f=;
while (!(ch>=''&&ch<='')) {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void add(int x,int y,int l)
{
edge[++tot]=(EDGE){x,y,head[x],l,};
head[x]=tot;
edge[++tot]=(EDGE){y,x,head[y],l,};
head[y]=tot;
}
void spfa(int x)
{
memset(dist,0x3f3f3f3f,sizeof(dist));
queue <int> q;
dist[x]=;vis[x]=;q.push(x);
while (!q.empty())
{
int k=q.front();q.pop();vis[k]=;
for (int i=head[k];i;i=edge[i].next)
{
int y=edge[i].to;
if (dist[y]>dist[k]+1ll*edge[i].l)
{
dist[y]=dist[k]+1ll*edge[i].l;
if (!vis[y])
{
vis[y]=;
q.push(y);
}
}
}
}
}
void get()
{
for (int i=;i<=n;i++)
{
if (a[i]) continue;
for (int j=head[i];j;j=edge[j].next)
{
int y=edge[j].to;
if (y==) continue;
if (dist[y]+1ll*edge[j].l==dist[i]) edge[j].fl=;
}
}
}
bool cmp(EDGE aa,EDGE bb) {return aa.l<bb.l;}
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
int main()
{
n=read();m=read();
for (int i=;i<=n;i++) a[i]=read();
for (int i=;i<=m;i++)
{
int u=read(),v=read(),l=read();
add(u,v,l);
}
for (int i=;i<=n;i++)
{
if (a[i]) add(S,i,);
fa[i]=i;
}
spfa(S);
get();
sort(edge+,edge++tot,cmp);
ll ans=;
int p=;
for (int i=;i<=tot;i++)
{
if (!edge[i].fl) continue;
int x=edge[i].from,y=edge[i].to;
int xx=find(x),yy=find(y);
if (xx!=yy)
{
fa[xx]=yy;
++p;
ans+=1ll*edge[i].l;
if (p==n-) break;
}
}
if (!ans) puts("impossible");
else cout<<ans<<endl;
return ;
}
[NOIP2015模拟10.22] 最小代价 解题报告 (最小生成树)的更多相关文章
- [NOIP2015模拟10.22] 最大子矩阵 解题报告(单调栈)
Description 我们将矩阵A中位于第i行第j列的元素记作A[i,j].一个矩阵A是酷的仅当它满足下面的条件: A[1,1]+A[r,s]<=A[1,s]+A[r,1](r,s ...
- [NOIP2015模拟10.27] 挑竹签 解题报告(拓扑排序)
Description 挑竹签——小时候的游戏夏夜,早苗和诹访子在月光下玩起了挑竹签这一经典的游戏.挑竹签,就是在桌上摆上一把竹签,每次从最上层挑走一根竹签.如果动了其他的竹签,就要换对手来挑.在所有 ...
- 【NOIP2015模拟10.22】最小代价
前言 本来在比赛上就想到最小生成树了,但不相信这道题那么简单,然后就没有然后了... 题目 给出一幅由n个点m条边构成的无向带权图. 其中有些点是黑点,其他点是白点. 现在每个白点都要与他距离最近的黑 ...
- [jzoj 5930] [NOIP2018模拟10.26】山花 解题报告 (质因数分类)
题目链接: http://172.16.0.132/senior/#contest/show/2538/2 题目: 小S决定从某一个节点$u$开始对其子树中与$u$距离小于$K$的节点代表的花树进行采 ...
- [JZOJ 5893] [NOIP2018模拟10.4] 括号序列 解题报告 (Hash+栈+map)
题目链接: https://jzoj.net/senior/#main/show/5893 题目: 题解: 考虑暴力怎么做,我们枚举左端点,维护一个栈,依次加入元素,与栈顶元素和栈内第二个元素相同时弹 ...
- [JZOJ 5905] [NOIP2018模拟10.15] 黑暗之魂(darksoul) 解题报告 (拓扑排序+单调队列+无向图基环树)
题目链接: http://172.16.0.132/senior/#main/show/5905 题目: oi_juruo热爱一款名叫黑暗之魂的游戏.在这个游戏中玩家要操纵一名有 点生命值的无火的余灰 ...
- JZOJ 4273. 【NOIP2015模拟10.28B组】圣章-精灵使的魔法语
4273. [NOIP2015模拟10.28B组]圣章-精灵使的魔法语 (File IO): input:elf.in output:elf.out Time Limits: 1000 ms Mem ...
- JZOJ 4269. 【NOIP2015模拟10.27】挑竹签
4269. [NOIP2015模拟10.27]挑竹签 (File IO): input:mikado.in output:mikado.out Time Limits: 1000 ms Memory ...
- JZOJ 4272. 【NOIP2015模拟10.28B组】序章-弗兰德的秘密
272. [NOIP2015模拟10.28B组]序章-弗兰德的秘密 (File IO): input:frand.in output:frand.out Time Limits: 1000 ms M ...
随机推荐
- 【转载】tslib移植_freescale imx6
本文来自网络:http://blog.csdn.net/xishuang_gongzi/article/details/49422879 环境:host:Ubuntu12.04target:frees ...
- extjs grid 复制问题还有一种解决方式.
之前的项目中尽管也常常使用到extjs,但也许是没有注意到,也也许是根本就没有须要用到这个功能. 前几天在和客户讨论需求时,客户说想要可以将gird表中的数据复制出来,当时没多想,感觉这功能extjs ...
- Leetcode--easy系列4
#58 Length of Last Word Given a string s consists of upper/lower-case alphabets and empty space char ...
- ADO.NET (二)—— ADO和ADO .NET对照
ADO.NET (二)-- ADO和ADO .NET对照 我们知道ADO.NET的两大核心组件各自是Data Provider和DataSet.假设说 DataSet是ADO.NET的心 ...
- ThinkPHP5.0框架开发--第8章 TP5.0 模型
ThinkPHP5.0框架开发--第8章 TP5.0 模型 第8章 TP5.0 模型 ================================================= 今日学习 1. ...
- ubuntu修改顶栏颜色
title: ubuntu修改顶栏颜色 toc: false date: 2018-09-29 19:14:01 categories: methods tags: Ubuntu 编辑shell主题的 ...
- hihocoder 1407 重复旋律2
思路: 二分一哈答案 height分个块 //By SiriusRen #include <cstdio> #include <cstring> #include <al ...
- 【实战经验】64位Win7安装+32位Oracle + PL/SQL 解决方法
软件环境:64位win7.32位Oracle 10g. PL/SQL 9.0.4.1644 前言:以前开发用的都是32位系统,突然换到64位上,安装环境真的有点麻烦了,尤其对于PL/SQL只支持32位 ...
- 乌班图 之 apt命令 及 VMware共享文件夹
apt是Advanced Packaging Tool ,是Ubuntu下的一个安装包管理工具 大部分软件的安装.更新.卸载 都是利用apt命令来实现 直接在终端输入apt即可查阅命令的帮助信息 常用 ...
- POJ 1273 Drainage Ditches【最大流】
题意:给出起点是一个池塘,M条沟渠,给出这M条沟渠的最大流量,再给出终点是一条河流,问从起点通过沟渠最多能够排多少水到河流里面去 看的紫书的最大流,还不是很理解,照着敲了一遍 #include< ...