鏈接:https://ac.nowcoder.com/acm/contest/548/C
來源:牛客網
題目描述
立華奏是一個剛剛開始學習 OI 的萌新。
最近,實力強大的 Qingyu 當選了 IODS 9102 的出題人。衆所周知, IODS 是一場極其毒瘤的比賽。爲了在這次比賽中取得好的成績,立華奏決定學習可能考到的每一個知識點。
在Qingyu 的博客中,立華奏得知這場比賽總共會考察選手 n 個知識點。此前,立華奏已經依靠自學學習了其中 k 個知識點。接下來,立華奏需要學習其他的知識點,每學習一個單獨的知識點,需要消耗的時間爲 Ti 天。同時,某些知識點之間存在聯繫,可以加速學習的過程。經過計算,立華奏一共發現了其中 m 種聯繫,第 i 種聯繫可以表示爲(Xi,Yi,Hi),其含義爲“在掌握了第 Xi 個知識點和第 Yi 個知識點中任意一個後,學習 Hi 天即可掌握另一個知識點”。
留給立華奏的時間所剩無幾,只有 t 天,因此,她想知道自己能不能在這 t 天內學習完成所有的知識點。
輸入描述:
本題輸入量較大,請注意使用效率較高的讀入方式
輸入的第一行包含四個整數 n, m, k, t,含義見上所述。
接下來一行,包含 n 個整數,依次表示 T1,T2,⋯,Tn
接下來一行,包含 k 個整數,表示立華奏已經學習過的知識點。如果 k=0,則此處爲一空行。
接下來 m 行,每行 3 個整數 Xi,Yi,Hi,描述一種聯繫。
輸出描述:
如果立華奏能夠學習完所有的知識點,輸出一行 Yes。否則輸出 No
示例1
輸入
4 3 2 5
4 5 6 7
2 3
1 2 3
1 3 2
3 4 2
輸出
Yes
說明
立華奏已經學習過了第 2, 3 個知識,由第 2 個關係,立華奏可以花 2 天學會知識點 1,在由關係 3, 立華奏可以 2 天學會知識點 4,因此總共需要花費 4 天,可以完成任務。
示例2
輸入
5 4 0 12
4 5 6 7 1
1 2 3
1 3 2
3 4 2
1 5 233
輸出
Yes
說明
立華奏比較菜,因此什麼都沒有學過。她可以選擇先花 4 天的時間學會知識點 1。然後根據關係 1, 2,分別花 3, 2 天的時間學會知識點 2, 3,再根據關係 3,花 2 天的時間學會知識點 4。然後,她再單獨學習知識點 5,花費1天,總共花費了 12 天 ,可以完成任務。
請注意,雖然關係 4 允許立華奏在知識點 1 的基礎上學習知識點 5,但需要的時間比單獨學習還要多,因此立華奏不會在知識點 1 的基礎上學習知識點 5.
備註:
0⩽k⩽n⩽10^6,
m⩽5×10^6,
t⩽10^18,
Ti,Hi⩽10^3
題解:
崩潰了,Java過不去,同樣的寫法,c秒過。。
用一個虛點0連接所有的知識點,權值爲知識點的學習時間。如果學習過了這個點,就連一條權值爲0的邊。
然後跑最小生成樹,看權值之和是否小於給定時間t。除了計數排序優化沒有用上,其他的優化用了之後還是最多隻過了76.92%
代碼:
//崩潰了,Java過不去,同樣的寫法,c秒過。。
//用一個虛點0連接所有的知識點,權值爲知識點的學習時間。如果學習過了這個點,就連一條權值爲0的邊。
//然後跑最小生成樹,看權值之和是否小於給定時間t。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Main {
static class edge implements Comparable<edge>{
int v,next,c;
public edge(int v, int next, int c) {
super();
this.v = v;
this.next = next;
this.c = c;
}
@Override
public int compareTo(edge o) {
return this.c-o.c;
}
}
static edge e[]=new edge[6000005];
static int height[]=new int[1000005];
static int fa[]=new int[1000005];
static int eid=0;
static void insert(int u,int v,int c){
e[eid]=new edge(u,v,c);
eid++;
}
static int find(int x){
return x==fa[x]?x:(fa[x]=find(fa[x]));
}
static int n,m,k;
public static void main(String[] args) throws IOException {
StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
long t;
st.nextToken();
n=(int)st.nval;
st.nextToken();
m=(int)st.nval;
st.nextToken();
k=(int)st.nval;
st.nextToken();
t=(long)st.nval;
int tn[]=new int[n+1];
for(int i=1;i<=n;i++){
st.nextToken();
tn[i]=(int)st.nval;
fa[i]=i;
}
while(k-->0){
st.nextToken();
int temp=(int)st.nval;
tn[temp]=0;
}
for(int i=1;i<=n;i++){
insert(0,i,tn[i]);
}
int x,y,h;
for(int i=0;i<m;i++){
st.nextToken();
x=(int)st.nval;
st.nextToken();
y=(int)st.nval;
st.nextToken();
h=(int)st.nval;
insert(x,y,h);
}
if(t>1000*eid){
System.out.println("Yes");
return;
}
Arrays.sort(e,0,eid);
long sum=0;
int num=0;
for(int i=0;i<eid;i++){
int a=find(e[i].v);
int b=find(e[i].next);
int w=e[i].c;
if(a!=b){
if(height[a]>height[b]){//啓發式合併,把節點深度小的樹合併到節點深度大的樹下。
fa[b]=a;
}else{
fa[a]=b;
if(height[a]==height[b])
{
height[b]++;
}
}
num++;
sum+=w;
}
if(sum>t||num==n-1)
break;
}
//System.out.println(sum);
if(sum<=t)
System.out.println("Yes");
else
System.out.println("No");
}
}