题目地址:cf#234_div2_D
题目大意:
现在又k类细菌,现在已知每一类细菌的编号,给一些非负路径,问1 是否满足每类细菌之间有权值0的路径,2 当满足1时,输出类之间的距离矩阵。
1 以0权值到达是等价关系,所以是等价类,引入并查集
2 给一个标号,我们应能知道它属于哪一个类别。
3 输入的边,可能很多条是连接同一对类型的,所以在使用Floyd之前还是要取min
4 符号优先级 慎用三目运算符
#include<iostream>
#include<cstdio>
using namespace std;
#define INF 1000000001
int n,m,k;
int p[100005]; // 并查集
int t[100005]; // 记录种类
int c[505];
int cc[505];
//struct edge
//{
// int u;
// int v;
// int x;
//};
//
//edge e[100005];
long long d[505][505];
void init()
{
for(int i=0;i<n;i++) // 并查集初始化
p[i]=i;
cc[0]=c[0];
for(int i=1;i<k;i++)// 前i类的和初始化
{
cc[i]=cc[i-1]+c[i];
}
int index=0;
for(int i=0;i<k;i++) // t[i]表示i的类型
{
for(int j=0;j<c[i];j++)
{
t[index++]=i;
}
}
for(int i=0;i<k;i++)
for(int j=0;j<k;j++)
d[i][j]=(i==j?0:INF);
}
int find(int x)
{
return p[x]==x?x:p[x]=find(p[x]);
}
void floyd()
{
for(int l=0;l<k;l++)
for(int i=0;i<k;i++)
for(int j=0;j<k;j++)
if(d[i][l]!=INF&&d[l][j]!=INF)
d[i][j]=d[i][j]<d[i][l]+d[l][j]?d[i][j]:d[i][l]+d[l][j];
}
int main()
{
cin>>n>>m>>k;
int u,v,x;
for(int i=0;i<k;i++)
cin>>c[i];
init();
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&x);
int tu=t[u-1];
int tv=t[v-1];
if(x==0) // 不可 x==0&&tu==tv 有可能借助其他类的细菌当桥梁
{
int xx=find(u-1);
int yy=find(v-1);
if(xx!=yy) p[xx]=yy;
}
if(tu!=tv)
{
d[tu][tv]=d[tu][tv]<x?d[tu][tv]:x; // 记住还是取min
d[tv][tu]=d[tu][tv];
}
}
bool flag=0;
for(int i=0;i<k;i++)
{
for(int j=1;j<c[i];j++)
{
int before=i==0?0:cc[i-1]; // 注意优先级,find(i==0?0:cc[i-1]+j) 不可以的
if(find(before+j)!=find(before))
{
flag=1;
break;
}
}
}
if(flag==1) cout<<"No"<<endl;
else
{
cout<<"Yes"<<endl;
floyd();
for(int i=0;i<k;i++)
{
for(int j=0;j<k;j++)
{
if(j!=0) cout<<" ";
if(d[i][j]!=INF) cout<<d[i][j];
else cout<<-1;
}
cout<<endl;
}
}
}