D. Dima and Bacteria
题意: 给n个点,与m条无向边,将n个点分为k个集合,要求集合内的点相互可以到达,且权值为0,输出各集合之间的最短路,若是集合之间不能到达,则输出-1;
思路: 用并查集解决集合内部是否相互可以到达,然后求各个集合的最短路
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+5;
int fa[N];
int mp[505][505];
int num[505];
int n,m,k;
int a[N];
int fid(int x)
{
if(fa[x]==x)
return x;
return fa[x]=fid(fa[x]);
}
int judge()
{
int cnt=1;
for(int i=1;i<=k;i++)
{
int u=fid(cnt);
for(int j=1;j<=num[i];j++)
{
int v=fid(cnt);
if(u!=v)
return 0;
cnt++;
}
}
return 1;
}
void floyd()
{
for(int i=1;i<=k;i++)
mp[i][i]=0;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
for(int u=1;u<=k;u++)
{
mp[j][u]=min(mp[j][u],mp[j][i]+mp[i][u]);
}
}
}
}
int main()
{
memset(mp,0x3f,sizeof mp);
scanf("%d%d%d",&n,&m,&k);
int cnt=1;
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
for(int i=1;i<=k;i++)
{
//int num;
scanf("%d",&num[i]);
for(int j=1;j<=num[i];j++,cnt++)
{
a[cnt]=i;
}
}
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(w==0)
{
int u1=fid(u);
int v1=fid(v);
if(u1!=v1)
fa[v1]=u1;
}
mp[a[v]][a[u]]=mp[a[u]][a[v]]=min(mp[a[u]][a[v]],w);
}
if(judge())
{
floyd();
printf("Yes\n");
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(k==j)
printf("%d\n", mp[i][j]!=INF ? mp[i][j] : -1);
else
printf("%d ", mp[i][j]!=INF ? mp[i][j] : -1);
}
}
}
else
printf("No\n");
return 0;
}