NOIP模拟 Minimum

T2:Minimum

【题目描述】

    给出一幅由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     (选2、4、6)

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

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

        首先还是30%的数据:枚举每条边的选取情况,暴力判断;

   然后就是100%的数据:我们添加一个超级点S,在S与每个黑点之间连一条权值为0的边,先处理从S出发到每个点的最短距离,我们可以取出一张最短路径图,现在问题就变成了取权值最小的边的集合,使得这幅图连接,那么,最小生成树的算法就能AC此题。

贴代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN=1e6+10;
const ll MAXM=2e6+10;
const ll INF=0x3f3f3f3f;

ll Read()
{
	ll i=0,f=1;
	char c;
	for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
	if(c=='-')
	  f=-1,c=getchar();
	for(;c>='0'&&c<='9';c=getchar())
	  i=(i<<1)+(i<<3)+c-'0';
	return i*f;
}

ll n,m,cnt;
ll dis[MAXN],head[MAXN],nxt[MAXM];
ll fa[MAXN];
priority_queue<pair<int,int> > q;
struct edge{
	int from,to,w;
}e[MAXM],t[MAXM];

void add(int a,int b,int c)
{
	cnt++;
	nxt[cnt]=head[a];
	head[a]=cnt;
	e[cnt].from=a;
	e[cnt].to=b;
	e[cnt].w=c;
}

bool cmp(edge a,edge b)
{
	return a.w<b.w;
}

int find(int x)
{
	if(fa[x]!=x)
	  fa[x]=find(fa[x]);
	return fa[x];
}

void dijkstra(ll st)
{
	memset(dis,INF,sizeof(dis));
	dis[st]=0;
	q.push(make_pair(0,st));
	while(!q.empty())
	{
		int u=q.top().second;
		q.pop();
		for(int i=head[u];i!=-1;i=nxt[i])
		{
			int v=e[i].to;
			if(dis[v]>dis[e[i].from]+e[i].w)
			{
				dis[v]=dis[e[i].from]+e[i].w;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}

int main()
{
	memset(head,-1,sizeof(head));
	memset(nxt,-1,sizeof(nxt));
	n=Read(),m=Read();
	for(ll i=1;i<=n;++i)
	{
		int col=Read();
		if(col)
		{
			add(i,0,0);
			add(0,i,0);
		}
	}
	for(ll i=1;i<=m;++i)
	{
		ll x,y,z;
		x=Read(),y=Read(),z=Read();
		add(x,y,z);
		add(y,x,z);
	}
	dijkstra(0);
	ll tcnt=cnt;
	cnt=0;
	for(int i=1;i<=tcnt;++i)
	{
		if(dis[e[i].from]+e[i].w==dis[e[i].to]||dis[e[i].from]==dis[e[i].to]+e[i].w)
		{
			t[++cnt].from=e[i].from;
			t[cnt].to=e[i].to;
			t[cnt].w=e[i].w;
		}
	}
	sort(t+1,t+cnt+1,cmp);
	for(ll i=1;i<=n;++i)
	  fa[i]=i;
	ll ans=0,suc=0;
	for(ll i=1;i<=cnt;++i)
	{
		ll a=find(t[i].from),b=find(t[i].to);
		if(a!=b)
		{
			ans+=t[i].w;
			suc++;
			fa[a]=b;
		}
	}
	if(suc!=n)
	{
		cout<<"impossible";
	}
	else
	  cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/81382591