博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[NOIP2015模拟10.22] 最小代价 解题报告 (最小生成树)
阅读量:5231 次
发布时间:2019-06-14

本文共 2412 字,大约阅读时间需要 8 分钟。

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=1;i<=n;i++)    {        if (a[i]) continue;        for (int j=head[i];j;j=edge[j].next)        {            int y=edge[j].to;            if (y==0) continue;            if (dist[y]+1ll*edge[j].l==dist[i]) edge[j].fl=1;        }    }}

也就是说我们枚举每一个白点连的边,如果dist是通过这条边去更新的那么就fl赋值为1,表示它属于最短路径图。于是对fl为1的边跑最小生成树就好了。

代码如下:

#include
#include
#include
#include
#include
#define ll long longusing namespace std;const int maxn=100000+50;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<<5];inline int read(){ char ch=getchar(); int s=0,f=1; while (!(ch>='0'&&ch<='9')) {
if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f;}void add(int x,int y,int l){ edge[++tot]=(EDGE){x,y,head[x],l,0}; head[x]=tot; edge[++tot]=(EDGE){y,x,head[y],l,0}; head[y]=tot;}void spfa(int x){ memset(dist,0x3f3f3f3f,sizeof(dist)); queue
q; dist[x]=0;vis[x]=1;q.push(x); while (!q.empty()) { int k=q.front();q.pop();vis[k]=0; 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]=1; q.push(y); } } } }}void get(){ for (int i=1;i<=n;i++) { if (a[i]) continue; for (int j=head[i];j;j=edge[j].next) { int y=edge[j].to; if (y==0) continue; if (dist[y]+1ll*edge[j].l==dist[i]) edge[j].fl=1; } }}bool cmp(EDGE aa,EDGE bb) { return aa.l

 

转载于:https://www.cnblogs.com/xxzh/p/9296727.html

你可能感兴趣的文章
MongoDB的数据库、集合的基本操作
查看>>
ajax向后台传递数组
查看>>
疯狂JAVA16课之对象与内存控制
查看>>
[转载]树、森林和二叉树的转换
查看>>
软件测试-----Graph Coverage作业
查看>>
django ORM创建数据库方法
查看>>
创建Oracle synonym 详解
查看>>
php7 新特性整理
查看>>
RabbitMQ、Redis、Memcache、SQLAlchemy
查看>>
linux查看端口占用
查看>>
Sql常见面试题 受用了
查看>>
知识不是来炫耀的,而是来分享的-----现在的人们却…似乎开始变味了…
查看>>
CSS背景颜色、背景图片、平铺、定位、固定
查看>>
口胡:[HNOI2011]数学作业
查看>>
我的第一个python web开发框架(29)——定制ORM(五)
查看>>
中国剩余定理
查看>>
基础笔记一
查看>>
uva 10137 The trip
查看>>
Count Numbers
查看>>
编写高质量代码改善C#程序的157个建议——建议110:用类来代替enum
查看>>