魔法宝石
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 254 Accepted Submission(s): 85
Problem Description
小s想要创造n种魔法宝石。小s可以用ai的魔力值创造一棵第i种魔法宝石,或是使用两个宝石合成另一种宝石(不消耗魔力值)。请你帮小s算出合成某种宝石的所需的最小花费。
Input
第一行为数据组数T(1≤T≤3)。
对于每组数据,首先一行为n,m(1≤n,m≤10^5)。分别表示魔法宝石种类数和合成魔法的数量。
之后一行n个数表示a1到an。(1≤ai≤10^9)。ai表示合成第i种宝石所需的魔力值。
之后m行,每行三个数a,b,c(1≤a,b,c≤n),表示一个第a种宝石和第b种宝石,可以合成一个第c种宝石。
Output
每组数据输出一行n个数,其中第i个数表示合成第i种宝石的魔力值最小花费。
Sample Input
1
3 1
1 1 10
1 2 3
Sample Output
1 1 2
题意
分析
由于一个宝石费用减少只会影响以它直接/间接为材料的宝石,故我们先根据宝石关系建邻接表,每次遇到有宝石费用减少,dfs处理一遍即可
题目不错,多复习
trick
似乎时间复杂度略高,数据较弱?
代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
struct node
{
int x,y,z;
}data[100100];
vector<node>mp[100100];
int a[100100];
void dfs(int z)
{
node temp;
for(int j=0;j<mp[z].size();j++)//每次找与z直接关联的点更新
{
temp=mp[z][j];
if(a[temp.z]>a[temp.x]+a[temp.y])
{
a[temp.z]=a[temp.x]+a[temp.y];
dfs(temp.z);
}
}
}
int main()
{
int t;
for(scanf("%d",&t);t--;)
{
int n,m;
mem(mp,0);
mem(a,0);
mem(data,0);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int x,y,z;
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&x,&y,&z);
data[i]={x,y,z};
node temp;
temp.x=x,temp.y=y,temp.z=z;
mp[x].push_back(temp);//建双向边
temp.x=y,temp.y=x;
mp[y].push_back(temp);
}
for(int i=0;i<m;i++)
{
x=data[i].x,y=data[i].y,z=data[i].z;
if(a[z]>a[x]+a[y])
{
a[z]=a[x]+a[y];
dfs(z);
}
}
for(int i=1;i<=n;++i)printf("%d%c",a[i],i==n?'
':' ');
}
return 0;
}