题意:
有k种细菌,每种细菌c[i](i:1~k)个,总共n个,n个点之间有m条边,
第一个问题,相同种类的细菌之间能不能有一条花费为零的路。第二个问题,
在所有种类细菌均满足第一问条件的情况下,各个种类细菌之间的最短路。
思路:
相邻两点之间花费为零,必然连接他们的边权为零。所以很容易想到把所有
边权为零的边保留,然后看同种细菌是不是在一个联通块中即可。 并查集、dfs
理论上应该都行(dfs可能数据量大点,可以试一下,只写了并查集)。
然后各种类间最短路数据量较小,跑个弗洛伊德即可。
PS:两点间会有重边,inf的使用、防止爆精度。
AC代码:
#define LL long long
#define par pair<int,int>
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e5+100;
const int M=1e5+100;
int c[N];
int fat[N];
int find(int x)
{
if(x==fat[x])return x;
return fat[x]=find(fat[x]);
}
void unionn(int x,int y)
{
int fa=find(x),fb=find(y);
if(fa!=fb)fat[fa]=fb;
}
struct ee
{
int l,r,v;
}e[M];
LL f[600][600];
int cnt[N];
int main()
{
int n,m,k;
while(cin>>n>>m>>k)
{
memset(cnt,0,sizeof(cnt));
for(int i=0;i<=n;++i)fat[i]=i;
memset(c,0,sizeof(c));
for(int i=1;i<=k;++i)
{
f[i][i]=0;
for(int j=i+1;j<=k;++j)f[i][j]=f[j][i]=INF;
}
for(int i=1;i<=k;++i)cin>>c[i];
for(int i=1;i<=m;++i)
{
int x,y,z;
cin>>x>>y>>z;
if(z==0)
{
unionn(x,y);
}
e[i].l=x;
e[i].r=y;
e[i].v=z;
}
int sum=0;
bool flag=0;
for(int i=1;i<=k;++i)
{
int tmp=find(sum+1);
cnt[sum+1]=i;
for(int j=sum+2;j<=sum+c[i];++j)
{
cnt[j]=i;
if(tmp!=find(j))
{
flag=1;
break;
}
}
if(flag)break;
sum+=c[i];
}
if(flag)
{
cout<<"No"<<endl;
return 0;
}
else cout<<"Yes"<<endl;
for(int i=1;i<=m;++i)
{
int x=e[i].l;
int y=e[i].r;
int z=e[i].v;
if(cnt[x]==cnt[y])continue;
else
{
if(z<f[cnt[x]][cnt[y]])f[cnt[x]][cnt[y]]=f[cnt[y]][cnt[x]]=z;//*****
}
}
for(int kk=1;kk<=k;++kk)
for(int i=1;i<=k;++i)
for(int j=1;j<=k;++j)
{
if(f[i][kk]==INF||f[kk][j]==INF)continue;
if(f[i][kk]+f[kk][j]<f[i][j])f[i][j]=f[i][kk]+f[kk][j];
}
for(int i=1;i<=k;++i)
{
for(int j=1;j<=k;++j)
{
if(f[i][j]>=INF)f[i][j]=-1;
cout<<f[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}
The end;