Description

给出一幅由n个点m条边构成的无向带权图。
其中有些点是黑点,其他点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个黑点,可以选取其中任意一个),我们想要使得花费的代价最小。请问这个最小代价是多少?
注意:最后选出的边保证每个白点到离它最近的黑点的距离仍然等于原图中的最短距离。

Input

第一行两个整数n,m;
第二行n个整数,0表示白点,1表示黑点;
接下来m行,每行三个整数x,y,z,表示一条连接x和y点,权值为z的边。

Output

如果无解,输出impossible;
否则,输出最小代价。

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

对30%的输入数据:1≤n≤10,1≤m≤20;
对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] 最小代价 解题报告 (最小生成树)的更多相关文章

  1. [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 ...

  2. [NOIP2015模拟10.27] 挑竹签 解题报告(拓扑排序)

    Description 挑竹签——小时候的游戏夏夜,早苗和诹访子在月光下玩起了挑竹签这一经典的游戏.挑竹签,就是在桌上摆上一把竹签,每次从最上层挑走一根竹签.如果动了其他的竹签,就要换对手来挑.在所有 ...

  3. 【NOIP2015模拟10.22】最小代价

    前言 本来在比赛上就想到最小生成树了,但不相信这道题那么简单,然后就没有然后了... 题目 给出一幅由n个点m条边构成的无向带权图. 其中有些点是黑点,其他点是白点. 现在每个白点都要与他距离最近的黑 ...

  4. [jzoj 5930] [NOIP2018模拟10.26】山花 解题报告 (质因数分类)

    题目链接: http://172.16.0.132/senior/#contest/show/2538/2 题目: 小S决定从某一个节点$u$开始对其子树中与$u$距离小于$K$的节点代表的花树进行采 ...

  5. [JZOJ 5893] [NOIP2018模拟10.4] 括号序列 解题报告 (Hash+栈+map)

    题目链接: https://jzoj.net/senior/#main/show/5893 题目: 题解: 考虑暴力怎么做,我们枚举左端点,维护一个栈,依次加入元素,与栈顶元素和栈内第二个元素相同时弹 ...

  6. [JZOJ 5905] [NOIP2018模拟10.15] 黑暗之魂(darksoul) 解题报告 (拓扑排序+单调队列+无向图基环树)

    题目链接: http://172.16.0.132/senior/#main/show/5905 题目: oi_juruo热爱一款名叫黑暗之魂的游戏.在这个游戏中玩家要操纵一名有 点生命值的无火的余灰 ...

  7. JZOJ 4273. 【NOIP2015模拟10.28B组】圣章-精灵使的魔法语

    4273. [NOIP2015模拟10.28B组]圣章-精灵使的魔法语 (File IO): input:elf.in output:elf.out Time Limits: 1000 ms  Mem ...

  8. JZOJ 4269. 【NOIP2015模拟10.27】挑竹签

    4269. [NOIP2015模拟10.27]挑竹签 (File IO): input:mikado.in output:mikado.out Time Limits: 1000 ms  Memory ...

  9. JZOJ 4272. 【NOIP2015模拟10.28B组】序章-弗兰德的秘密

    272. [NOIP2015模拟10.28B组]序章-弗兰德的秘密 (File IO): input:frand.in output:frand.out Time Limits: 1000 ms  M ...

随机推荐

  1. ioctl.h 分析

    ioctl.h 分析 我自己画了个解析图...不要嫌弃丑啊.. . 哈哈 type The magic number. Just choose one number (after consulting ...

  2. django models.py增加后MySQL数据库中并没有生成相应的表

    根据教程到添加并保存quest的时候报错了 1.models.py里面的命名没有错 2.查看mysite->settiongs下的INSTALLED_APPS设置正确 3.使用python ma ...

  3. React-Native系列Android——Native与Javascript通信原理(一)

    React-Native最核心的是Native与Javascript之间的通信,并且是双向通信.Native层到Javascript层,Javascript层到Native层.虽说是两个方向,但实现上 ...

  4. iOS开发之UIAlertController的适配

    在iOS8中,只能用UIAlertController.而原来的UIAlertView及UIActionSheet已经被抛弃掉了.但是如果一台iOS 7 的手机运行到有UIAlertControlle ...

  5. Linux就该这么学 20181003(第四章Vim/shell/测试条件)

    参考链接https://www.linuxprobe.com/ vim文本编辑器 命令模式:控制光标移动,可对文本进行复制,黏贴,删除和查找工作 输入模式:正常的文本录入 末行模式:保存或退出文档,以 ...

  6. 10.ref regex unordered_set smartpoint

    ref引用不可以复制的对象 void print(std::ostream &os, int i) { os << i << endl; } //ref引用不可以复制的 ...

  7. Django(part3)

    URLConf:负责url到view的map,就是一个urls.py module,通常在project和app级别都要定义, #mysite/urls.py from django.conf.url ...

  8. (转载)android控件之WebView控件缩小

    android控件之WebView控件缩小 作者: 字体:[增加 减小] 类型:转载 时间:2013-05-16我要评论 发现这个控件挺好用,能自已控制进度条,而且这个控件的功能非常壮大,先上个简单的 ...

  9. Hibernate框架学习(二)——api详解

    一.Configuration对象 功能:配置加载类,用于加载主配置,orm元数据加载. //1.创建,调用空参构造(还没有读配置文件) Configuration conf=new Configur ...

  10. SpringBoot学习笔记(1)----环境搭建与Hello World

    简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配 ...