您的位置:首页 > 其它

NOIP2017 7.17模拟 Minimum (最短路+最小生成树)

2017-07-18 08:41 351 查看
题目描述:

给出一幅由 n 个点 m 条边构成的无向带权图。

其中有些点是黑点,另外点是白点。

现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个,连所有的),我们想要使得花费的代价最小。请问这个最小代价是多少?

注意:最后选出的边保证每个白点到黑点的距离任然是最短距离。(这句话题解代码也无法实现,就不管了)

输入:

第一行两个整数 n,m ;

第二行 n 个整数,0 表示白点,1 表示黑点;

接下来 m 行,每行三个整数 x,y,z ,表示一条连接 x 和 y 点,权值为 z 的边。

输出:

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

样例数据:

输入

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

输出

5

【数据范围】

对 30% 的输入数据 :1≤n≤10,1≤m≤20;

对 100% 的输入数据 :1≤n≤100000,1≤m≤200000,1≤z≤1000000000 。

题意:将所有白点和黑点通过在最短路上的路径连接,求最小代价,无解的情况是存在白点与黑点无法连通。通过分析我们可以发现,有解的情况可以分为两个问题考虑:

1、求最短路;

2.并找到在最短路上的边;

3、通过这些边跑一边最小生成树,统计边权之和。

对于第一个问题,因为是要求任意一个白点到任意一个黑点的距离,我们可以想到建一个超级点,由它向每一个黑点连一条边权为0的有向边,然后由这个超级点跑一次最短路(迪杰斯特拉或spfa),就行了;

对于第二个问题,由最短路的更新方法

if(dis[a]+val[i]<dis[to[i]])
dis[to[i]]=dis[a]+val[i];


我们可以想到,遍历每条边,满足dis[edge[i].start]==dis[edge[i].end+edge[i[.val那么这条边一定是最短路上的边,由此我们可以找到所有最短路上的边

对于第三个问题,裸的最小生成树,在此就不赘述了;

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<iomanip>
#include<iostream>
#include<cctype>
#include<queue>
using namespace std;
int n,m,tot,sup,cnt,len,fa[100005],next[500010],first[100005],to[500010];
long long dis[100005];
long long val[500010];
bool black[100005],ok=true;
//---------------------
priority_queue< pair<int,int> > que;
pair<int,int> temp;
//---------------------
struct node
{
int st,end;
long long val;
}a[400010];

bool cmp(const node&a,const node&b)
{
return a.val<b.val;
}
//---------------------
inline long long Readint()
{
long long i=0,f=1;
char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
//---------------------
inline void add(int x,int y,long long z)
{
next[++tot]=first[x];
first[x]=tot;
to[tot]=y;
val[tot]=z;
}
//---------------------
inline void djstra(int root)
{
dis[root]=0;
temp.first=0;
temp.second=root;
que.push(temp);
while(!que.empty()){
temp=que.top();
que.pop();
int a=temp.second;
for(int i=first[a];i;i=next[i]){
if(dis[a]+val[i]<dis[to[i]]){
dis[to[i]]=dis[a]+val[i];
pair<int,int> s;
s.first=-dis[to[i]];
s.second=to[i];
que.push(s);
}
}
}
}
//---------------------
inline int find(int x)
{
if(x==fa[x]) return x;
fa[x]=find(fa[x]);
return fa[x];
}
//---------------------
int main()
{
freopen("minimum.in","r",stdin);

n=Readint(),m=Readint();
memset(first,0,sizeof(first));
for(int i=0;i<=n;i++) fa[i]=i;
for(int i=0;i<=n;i++) dis[i]=1e16+7;
for(int i=1;i<=n;i++){
black[i]=Readint();
if(black[i]) add(sup,i,0);
}
for(int i=1;i<=m;i++){
int x,y;
long long z;
x=Readint(),y=Readint(),z=Readint();
add(x,y,z),add(y,x,z);
}
djstra(sup);

for(int i=1;i<=n;i++) if(dis[i]==1e16+7) ok=false;
if(!ok){
cout<<"impossible"<<endl;
return 0;
}
for(int i=1;i<=n;i++){
for(int p=first[i];p;p=next[p]){
if(dis[to[p]]==val[p]+dis[i]){
a[++len].st=i,a[len].end=to[p],a[len].val=val[p];
}
}
}
long long ans=0;
sort(a+1,a+1+len,cmp);
for(int i=1;i<=len;i++){
int fx=find(a[i].st),fy=find(a[i].end);
if(fx!=fy){
fa[fx]=fy;
ans+=a[i].val;
cnt++;
}
if(cnt==n-1) break;
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐