牛客練習賽 43 CTachibana Kanade Loves Review 最小生成樹(Java版失敗)

鏈接: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");
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章