题意:英文实在不行,大概描述一下,第一行给定n,m,k个集合(其实是k种细菌)。n代表n个点。(其实是n个细菌。)并且1到n编号。第二行给出k个集合的点数量。(其实是k种细菌的数量)。下面m行,给出m条边(其实是m种仪器。。)给出u,v,x代表编号为u的点(细菌),到编号为v的点,需要花费x的能量。
问的是是否满足同种细菌移动的能量为0。如果满足的话,输出一个k*k行的矩阵,代表不同集合(细菌)的点之间互相移动所需要最小的花费。
假如有一个集合无法到达另一个集合,输出-1.
题目实在是太抽象了。。。
简述,就是给你n个点,m条边。K个集合,k个集合的点数,满足每个集合任意两点之间移动所需要的花费为0。求的是任意两个集合移动所需要的花费。
思路:先给每个集合的点编号。然后存入图里面。然后用并查集判断是否满足同个集合任意两点距离为0。(相当于所有的点他们的关系构成一个集合)。
如果满足的话,接下来floyd 求传递闭包,算出任意两个集合的点移动所需要的花费,如果不能到达,令其值为负一。
注意:n,m的范围很大,输入要用long long or __int64。
上代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define N 100005
#define M 505
#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;
ll fa[N];
ll num[N];
ll belong[N];
ll mpt[M][M];
ll find(ll x) //查找
{
if(x!=fa[x])
fa[x]=find(fa[x]);
return fa[x];
}
void hebing(ll x,ll y) //并查集
{
x=find(x);
y=find(y);
fa[y]=x;
}
bool judge()
{
ll i,j,p;
p=1;
for(i=1; i<=k; i++)
{
int x=find(p);
for(j=1; j<=num[i]; j++)
if(find(p++)!=x)
return 0;
} //用并查集判断一个集合内的任意两点是否花费为0。
return 1;
}
void floyd() //floyd 算法求传递闭包。用边联通所有有关系的点,并且算出任意两点的最短距离
{
for(ll p=1; p<=k; p++)
{
for(ll i=1; i<=k; i++)
{
for(ll j=1; j<=k; j++)
{
mpt[i][j]=min(mpt[i][j],mpt[i][p]+mpt[p][j]);
}
}
}
}
int main()
{
ll i,j,p;
while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF)
{
memset(mpt,INF,sizeof(mpt));
for(i=1; i<=k; i++)
for(j=1; j<=k; j++)
{
if(i==j)
mpt[i][j]=mpt[j][i]=0;
else
mpt[i][j]=mpt[j][i]=INF; //初始化不同集合的边。
}
for(i=1; i<=n; i++)
fa[i]=i; //并查集的初始化
p=1;
for(i=1; i<=k; i++)
{
scanf("%lld",&num[i]); //一个集合
for(j=1; j<=num[i]; j++)
belong[p++]=i; //给每个集合的每个点编号
}
ll u,v,w,uu,vv;
while(m--)
{
scanf("%lld%lld%lld",&u,&v,&w);
if(!w)
hebing(u,v); //花费为0就合并。。
uu=belong[u]; //把编号存入图里
vv=belong[v]; //同上
mpt[uu][vv]=mpt[vv][uu]=min(mpt[uu][vv],w);
}
if(!judge())
{
printf("No\n"); //判断是否满足
continue;
}
printf("Yes\n");
floyd();
for(i=1; i<=k; i++)
{
for(j=1; j<=k; j++) //枚举所有的不同集合
{
if(i==j)
mpt[i][j]=0;
if(mpt[i][j]==INF) //不能到达
mpt[i][j]=-1; //令为负一
if(j<k)
printf("%lld ",mpt[i][j]);
else
printf("%lld",mpt[i][j]);
}
printf("\n");
}
}
return 0;
}