题意:
有n个点,m条边,一些点属于一些集合,问集合到集合的距离及是否满足一个集合内的任意两点都存在距离为0的路径。
思路:
最短路+并查集判断是否任意两点都存在距离为0的路径。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 100005
#define MAXN 200005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;
ll n,m,k,ans,cnt,tot,flag;
ll c[maxn],sum[maxn],now,oo;
ll dist[505][505];
ll pre[maxn],fa[505];
ll Find(ll x)
{
if(x==pre[x]) return x;
pre[x]=Find(pre[x]);
return pre[x];
}
void Merge(ll x,ll y)
{
ll u=Find(x), v=Find(y);
if(x!=y) pre[u]=v;
}
int main()
{
ll i,j,t,u,v;
while(~scanf("%I64d%I64d%I64d",&n,&m,&k))
{
sum[0]=0;
for(i=1; i<=k; i++)
{
scanf("%I64d",&c[i]);
sum[i]=sum[i-1]+c[i];
}
for(i=1;i<=n;i++) pre[i]=i;
ll u,v,w;
memset(dist,0x3f,sizeof(dist));
oo=dist[0][0];
for(i=1; i<=m; i++)
{
scanf("%I64d%I64d%I64d",&u,&v,&w);
ll posu=lower_bound(sum+1,sum+k+1,u)-sum;
ll posv=lower_bound(sum+1,sum+k+1,v)-sum;
dist[posu][posv]=dist[posv][posu]=min(dist[posu][posv],w);
if(w==0) Merge(u,v);
}
memset(fa,0,sizeof(fa));
flag=1;
for(i=1;i<=n;i++)
{
ll posu=lower_bound(sum+1,sum+k+1,i)-sum;
u=Find(i);
if(fa[posu])
{
if(u!=fa[posu])
{
flag=0;
break ;
}
}
else
{
fa[posu]=u;
}
}
if(flag) printf("Yes\n");
else
{
printf("No\n");
continue ;
}
for(i=1;i<=k;i++) dist[i][i]=0;
for(ll p=1;p<=k;p++)
{
for(i=1;i<=k;i++)
{
for(j=1;j<=k;j++)
{
if(dist[i][j]>dist[i][p]+dist[p][j])
dist[i][j]=dist[i][p]+dist[p][j];
}
}
}
for(i=1; i<=k; i++)
{
for(j=1; j<=k; j++)
{
if(dist[i][j]>=oo) dist[i][j]=-1;
if(j==1) printf("%I64d",dist[i][j]);
else printf(" %I64d",dist[i][j]);
}
printf("\n");
}
}
return 0;
}