牛客网练习赛43-C(图论)

时间:2022-03-04 22:59:24

题目链接:https://ac.nowcoder.com/acm/contest/548/C

题意:有n个知识点,学会每个知识点花T[i],已经学会了其中k个知识点,有m组关系,t1,t2,t3,表示学会t2/t3之后学另一个知识点需要花H[i],时限为t,问能否在时限之前学完所有的知识点。

思路:将n个知识点编号为1..n,然后构造一个虚拟的知识点0,该知识点已经学会,且该知识点到其它知识点的距离分别是T[i],若知识点i已经学会了,则0到i的距离为0,m组关系对应m条边,这样就简化成了求最小生成树的问题了。将边按权值升序排序,利用kruskal算法就行了。但要注意的是题目的输入量十分大,达到了10的7次方,所以需要读入优化,不然会超时。

AC代码:

 #include<bits/stdc++.h>
using namespace std; inline int read(){
int x=,f=;char ch=;
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return f?-x:x;
} inline long long LLread(){
long long x=;int f=;char ch=;
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return f?-x:x;
} struct node{
int u,v,w;
}a[]; bool cmp(node x,node y){
return x.w<y.w;
} typedef long long LL;
int n,m,k,t,cnt,p,root[];
LL sum; void add(int x,int y,int z){
a[++p].u=x;
a[p].v=y;
a[p].w=z;
} int getr(int kk){
if(root[kk]==kk) return kk;
else return root[kk]=getr(root[kk]);
} int main(){
n=read(),m=read(),k=read(),t=LLread();
for(int i=;i<=n;++i)
root[i]=i;
for(int i=;i<=n;++i){
int tmp=read();
add(,i,tmp);
}
for(int i=;i<=k;++i){
int tmp=read();
add(,tmp,);
}
for(int i=;i<=m;++i){
int t1=read(),t2=read(),t3=read();
add(t1,t2,t3);
}
sort(a+,a+p+,cmp);
for(int i=;i<=p;++i){
int x=a[i].u,y=a[i].v,z=a[i].w,rx,ry;
rx=getr(x),ry=getr(y);
if(rx!=ry){
++cnt;
sum+=z;
root[ry]=rx;
}
if(cnt==n||sum>t) break;
}
if(cnt==n&&sum<=t) printf("Yes\n");
else printf("No\n");
return ;
}