1. 程式人生 > >最小生成樹--牛客練習賽43-C

最小生成樹--牛客練習賽43-C

space names truct str algo 接下來 題目 tchar 最小生成樹

牛客練習賽43-C

鏈接:

https://ac.nowcoder.com/acm/contest/548/C

來源:牛客網

題目描述

? 立華奏是一個剛剛開始學習 OI 的萌新。
最近,實力強大的 QingyuQingyu 當選了 IODS 9102 的出題人。眾所周知, IODS 是一場極其毒瘤的比賽。為了在這次比賽中取得好的成績,立華奏決定學習可能考到的每一個知識點。
在 QingyuQingyu 的博客中,立華奏得知這場比賽總共會考察選手 n 個知識點。此前,立華奏已經依靠自學學習了其中 k 個知識點。接下來,立華奏需要學習其他的知識點,每學習一個單獨的知識點,需要消耗的時間為 TiTi 天。同時,某些知識點之間存在聯系,可以加速學習的過程。經過計算,立華奏一共發現了其中 m 種聯系,第 i 種聯系可以表示為(Xi,Yi,Hi)(Xi,Yi,Hi),其含義為“在掌握了第 XiXi 個知識點和第 YiYi 個知識點中任意一個

後,學習 HiHi 天即可掌握另一個知識點”。
留給立華奏的時間所剩無幾,只有 t 天,因此,她想知道自己能不能在這 t 天內學習完成所有的知識點。

輸入描述:

本題輸入量較大,請註意使用效率較高的讀入方式
輸入的第一行包含四個整數 n, m, k, t,含義見上所述。

接下來一行,包含 n 個整數,依次表示 T1,T2,?,TnT1,T2,?,Tn接下來一行,包含 k 個整數,表示立華奏已經學習過的知識點。如果 k=0,則此處為一空行。
接下來 m 行,每行 3 個整數 Xi,Yi,HiXi,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?106,m?5×106,t?1018,Ti,Hi?103

思路

最小生成樹的變形,把點本身的值換成路徑上的權重

代碼

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#include <sstream>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <iomanip>
#include <stack>
#include <climits>
#include <fstream>
 
using namespace std;
 
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = 1000005;
const int MOD = 1e9 + 7;
 
#define F(i, l, r) for(int i = l;i <= (r);++i)

int read()
{
    int ret = 0, f = 1;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
    while(c >= '0' && c <= '9'){ret = (ret << 3) + (ret << 1) + c - '0';c = getchar();}
    return ret * f;
}
 
struct Edge
{
    int u, v, w;
    bool operator < (const Edge a) const
    {
        return w < a.w;
    }
}edge[N * 6];
int n, m, k, vis[N], fa[N], H[N];
LL t;
 
int Find(int x)
{
    return fa[x]?fa[x] = Find(fa[x]):x;
}
 
int main()
{
    int num = 0;
    n = read();m = read();k = read();scanf("%lld", &t);
    F(i, 1, n)H[i] = read();
    F(i, 1, k)H[read()] = 0;
    F(i, 1, n)edge[num++] = (Edge){0, i, H[i]};//把點的權重變成邊
    F(i, 1, m){edge[num].u = read();edge[num].v = read();edge[num++].w = read();}
 
    sort(edge, edge + num);
    LL sum = 0;
    F(i, 0, num - 1)
    {
        int x = Find(edge[i].u), y = Find(edge[i].v);
        if(x != y)
        {
            fa[x] = y;
            sum += edge[i].w;
        }
    }
    puts(sum > t?"No":"Yes");
    return 0;
}

最小生成樹--牛客練習賽43-C