日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

$Self~Problem~C~:~Samsara$

發(fā)布時(shí)間:2023/12/15 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 $Self~Problem~C~:~Samsara$ 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目背景:

在這個(gè)\(Canman\)界的人都知道,世界上最偉大的修道者 —— \(Felling\),曾經(jīng)結(jié)束了\(Canman\)的無(wú)垠盞之災(zāi),守護(hù)了\(Canman\)的和平。在無(wú)垠盞之災(zāi)的最后,近神的\(Felling\)正在和墮入魔道的修道者,無(wú)垠災(zāi)的始作俑者\(Neyii\)進(jìn)行最后的對(duì)峙。掌握著輪回之力的他,可以逆向流逝輪回,造成外爆內(nèi)斂的奇點(diǎn)爆炸,比一般的爆炸要強(qiáng)悍數(shù)倍。

題目描述:

已知當(dāng)前\(Neyii\)張開(kāi)魔疆,把\(Felling\)包圍了進(jìn)去。\(Felling\)在魔疆中實(shí)力受到大幅的限制,甚至連時(shí)間和空間之力都被禁止了。但是魔疆是一把雙面刃,包圍了\(Felling\)的同時(shí),\(Neyii\)也將自己的經(jīng)絡(luò)暴露在了\(Felling\)的面前。\(Felling\)知道這樣下去自己終將隕落,所以打算孤注一擲,利用自己的輪回之力,引爆\(Neyii\)的經(jīng)絡(luò)!

已知當(dāng)前\(Neyii\)的經(jīng)絡(luò)圖由成百上千的穴位和經(jīng)脈鏈接而成,經(jīng)脈負(fù)責(zé)聯(lián)通各個(gè)穴位。習(xí)武之人皆知,經(jīng)脈內(nèi)運(yùn)氣的流動(dòng)是單向的,否則將會(huì)導(dǎo)致運(yùn)氣沖突,經(jīng)脈爆裂的嚴(yán)重后果。如果引爆一個(gè)穴位,那么以這個(gè)穴位為起點(diǎn)的經(jīng)脈都會(huì)報(bào)廢。而如果一個(gè)穴位沒(méi)有任何經(jīng)脈流入供應(yīng),那么這個(gè)穴位就會(huì)進(jìn)入閉脈狀態(tài),使\(Felling\)無(wú)法對(duì)其催動(dòng)奇點(diǎn)爆炸。而\(Felling\)所引爆的穴位所蘊(yùn)含的能量都將返還\(Felling\)?,F(xiàn)在\(Felling\)所能釋放奇點(diǎn)爆炸的次數(shù)已經(jīng)不多了,他想在至多\(K\)次爆炸內(nèi),獲得盡量多的能量。當(dāng)然不一定要用完\(K\)次爆炸。題目不保證沒(méi)有環(huán), 但保證沒(méi)有重邊。保證權(quán)值不為負(fù)數(shù),沒(méi)有自環(huán)。

輸入格式:

第一行,三個(gè)正整數(shù)\(N, M, K\)表示穴位數(shù)和經(jīng)脈數(shù)和最多的爆炸次數(shù)。

第二行,\(N\)個(gè)整數(shù)\(Data[i]\),分別表示第\(i\)號(hào)穴位的能量。

下面\(M\)行,每行三個(gè)正整數(shù),\(X, Y\)表示從\(X\)\(Y\)有一條單向流動(dòng)的經(jīng)脈。

輸出格式:

一行,一個(gè)整數(shù),表示最多能獲得的能量數(shù)。

輸入樣例 :

7 7 3 10 2 8 4 9 5 7 1 2 1 3 1 4 2 5 3 6 3 7 4 7

輸出樣例:

24

數(shù)據(jù)大小:

對(duì)于\(10\)%的數(shù)據(jù),\(1 \leq N \leq 10, 1 \leq M \leq 20\)。

對(duì)于另外\(30\)%的數(shù)據(jù),經(jīng)絡(luò)圖無(wú)環(huán)。

對(duì)于另外\(10\)%的數(shù)據(jù),有且只有一個(gè)點(diǎn)的入度為\(0\)。

對(duì)于\(100\)%的數(shù)據(jù):\(1 \leq N \leq 10000\)\(1 \leq M \leq 500003\)\(1 \leq K \leq 100003\)

所有邊權(quán)\(\leq 1000\)


首先簡(jiǎn)化一下題面:

你現(xiàn)在有一張\(N\)個(gè)點(diǎn)\(M\)條邊的一般有向圖,你可以造成至多\(K\)次點(diǎn)上的爆炸,每次爆炸都可以獲得這個(gè)點(diǎn)的點(diǎn)權(quán)。爆炸之后所有以這個(gè)點(diǎn)為起點(diǎn)的出邊都會(huì)報(bào)廢。如果一個(gè)點(diǎn)沒(méi)有入邊,那么不可以實(shí)施爆炸。請(qǐng)求最大化點(diǎn)權(quán)和。

首先我們考慮一張有向無(wú)環(huán)圖。

你可以發(fā)現(xiàn),假如你現(xiàn)在想要引爆\(Now_1\)\(Now_2\),如果\(Now_2\)是從\(Now_1\)來(lái)的,那么我們一定是先引爆\(Now_2\),然后引爆\(Now_1\)獲得的價(jià)值更大。

比如上圖的\(3和\)\(6\)節(jié)點(diǎn),如果我想要引爆這兩個(gè)節(jié)點(diǎn),那么我一定先引爆\(6\),因?yàn)槿绻蚁纫?span id="ozvdkddzhkzd" class="math inline">\(3\),那么會(huì)導(dǎo)致\(6\)不能被引爆。

而如果\(Now_1\)\(Now_2\)是類(lèi)似于一種“并列關(guān)系”的話,就不用彼此考慮。就比如\(3\)\(4\)。

所以我們可以發(fā)現(xiàn)這個(gè)\(DAG\)上除了入度為\(0\)的那些點(diǎn)以外,其它的點(diǎn)我們都可以選。因?yàn)榭傆幸环N合法順序可以讓我們選完所有的點(diǎn)。因此\(DAG\)上我們只要?jiǎng)h去所有入度為\(0\)的點(diǎn),然后排序\(For\)\(K\)即可。\(30\)分到手。

那么我們來(lái)考慮下圖這種情況。

我們可以發(fā)現(xiàn),如果我們從\(4\)開(kāi)始引爆,那么\(4\)后引爆\(3\)\(3\)后引爆\(2\)\(2\)之后只剩了一個(gè)\(1\)沒(méi)有引爆。當(dāng)然換一個(gè)起點(diǎn)也是一樣的。所以說(shuō),我們只需要舍棄一個(gè)點(diǎn),那么其它的點(diǎn)都是可以被選中的。那么我們當(dāng)然刪去最小的點(diǎn)。

那么轉(zhuǎn)而來(lái)看一般有向圖。

我們發(fā)現(xiàn)這個(gè)情況下,原來(lái)的\(\{1, 2, 3, 4\}\)環(huán)都可以選了,因?yàn)槎嗔艘粋€(gè)入邊\(\{5 - > 1\}\),那么我們發(fā)現(xiàn)\(\{1, 2, 3, 4\}\)就可以看做是一個(gè)點(diǎn)。

那么得出算法:對(duì)于每一個(gè)強(qiáng)連通分量:

如果該強(qiáng)聯(lián)通分量有入度,那么這個(gè)強(qiáng)聯(lián)通分量里面的所有的點(diǎn)都可以選擇。

如果該強(qiáng)聯(lián)通分量沒(méi)有入度,那么去掉一個(gè)點(diǎn)之后,其余的所有的點(diǎn)都可以選擇。

所以算法流程如下:

  • 縮點(diǎn)
  • 對(duì)于每一條邊,如果從\(SCC_1\)跑到了\(SCC_2\),那么認(rèn)為\(SCC_2\)有入度,標(biāo)記\(Flag[SCC_2] = 1\)
  • \(for\)所有的\(SCC_i\),若\(Flag[SCC_i] == 1\)那么將該\(SCC\)里面的所有點(diǎn)加入數(shù)組。否則去掉里面點(diǎn)權(quán)最小的點(diǎn),然后將其余的點(diǎn)加入數(shù)組。
  • 對(duì)于上面說(shuō)的那個(gè)數(shù)組,用\(nth\_element\)排序前\(K\)大,然后計(jì)算點(diǎn)權(quán)和。

  • 算法實(shí)際上是一個(gè)比較奇妙的貪心。


    標(biāo)程:

    #include <algorithm> #include <iostream> #include <algorithm> #include <cstdlib> #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <cmath> #include <map> #define For1(i, A, B) for(register int i = (A), i##_end_ = (B); i <= i##_end_; ++ i) #define For2(i, A, B) for(register int i = (A), i##_end_ = (B); i >= i##_end_; -- i) #define MEM(Now, K) memset(Now, K, sizeof(Now)) #define CPY(Now, K) memcpy(Now, K, sizeof(Now)) #define Debug(Now) (cerr << Now << endl) #define Min(A, B) (A < B ? A : B) #define Max(A, B) (A < B ? B : A) #define SCPY(A, B) strcpy(A, B) #define Inf 0x7fffffff #define RE register #define IL inline #define MAXN 100010 #define MAXM 500010 #define _X first #define _Y second using namespace std ;typedef unsigned long long ULL ; typedef pair<long long, int> PLI; typedef pair<int, int> PII; typedef unsigned int UINT; typedef long double LDB; typedef long long LL ; typedef double DB ;IL int Read(){LL X = 0, F = 1 ; char ch = getchar() ;while(ch < '0' || ch > '9'){ if(ch == '-') F = - 1 ; ch = getchar() ; }while(ch <= '9' && ch >= '0') X = (X << 1) + (X << 3) + (ch ^ 48), ch = getchar() ;return X * F ; } IL double DBRead(){double X = 0, Y = 1.0 ; LL W = 0 ; char ch = 0 ;while(! isdigit(ch)) { W |= ch == '-' ; ch = getchar() ; }while(isdigit(ch)) X = X * 10 + (ch ^ 48), ch = getchar() ;ch = getchar();while(isdigit(ch)) X += (Y /= 10) * (ch ^ 48), ch = getchar() ;return W ? - X : X ; } IL void Print(/*LL*/ LL X){if(X < 0) putchar('-'), X = - X ;if(X > 9) Print(X / 10) ; putchar(X % 10 + '0') ;//cout << endl ;//cout << " " ; }//----------------------------------以上是精致小巧的缺省源......LL N, M, K, Data[MAXN], Ans ; struct Node{LL From, To, Next ; }Edge[MAXM] ; LL Head[MAXN], Total ; void Add(LL F, LL T){Total ++ ;Edge[Total].From = F ;Edge[Total].To = T ;Edge[Total].Next = Head[F] ;Head[F] = Total ; } LL Dfn[MAXN], Low[MAXN], Deep, Cnt, Flag[MAXN] ; LL Stack[MAXN], Insta[MAXN], Top ; LL Belong[MAXN], Est[MAXN], MIN[MAXN] ; LL Finally[MAXN], All ; //Finally表示最終的答案數(shù)組 //All表示“預(yù)選”答案一共有多少個(gè)。 void Tarjan(LL Now){ //縮點(diǎn)自然不用說(shuō)Dfn[Now] = Low[Now] = ++ Deep ;Stack[++ Top] = Now ; Insta[Now] = 1 ;for(LL i = Head[Now]; i; i = Edge[i].Next){if(! Dfn[Edge[i].To]){Tarjan(Edge[i].To) ;Low[Now] = min(Low[Now], Low[Edge[i].To]) ;} else if(Insta[Edge[i].To])Low[Now] = min(Low[Now], Dfn[Edge[i].To]) ;}if(Low[Now] == Dfn[Now]){Cnt ++ ; LL Pass ;do{Pass = Stack[Top --] ;if(Est[Cnt] > Data[Pass])MIN[Cnt] = Pass, Est[Cnt] = Data[Pass] ;//MIN[]和EST[]求的是每一個(gè)SCC里面最小的點(diǎn)//其中MIN[]是表示點(diǎn),EST[]表示點(diǎn)權(quán)Belong[Pass] = Cnt ;Insta[Pass] = 0 ;}while(Now != Pass) ;} } bool CMP(LL X, LL Y){return X > Y ; } int main() {N = Read(), M = Read(), K = Read() ;memset(Est, 127, sizeof(Est)) ;for(LL i = 1; i <= N; i ++)Data[i] = Read() ;for(LL i = 1; i <= M; i ++){LL F = Read(), T = Read() ;Add(F, T) ;}for(LL i = 1; i <= N; i ++)if(! Dfn[i]) Tarjan(i) ;// 縮點(diǎn)//下面這一行是一個(gè)判斷。如果存在一條邊使得這條邊從SCC1到SCC2//那么SCC2就屬于我們說(shuō)的又入度的強(qiáng)聯(lián)通分量。for(LL i = 1; i <= M; i ++){if(Belong[Edge[i].From] != Belong[Edge[i].To])Flag[Belong[Edge[i].To]] = 1 ;//Flag[]記錄這個(gè)SCC有沒(méi)有入度。}for(LL i = 1; i <= Cnt; i ++)if(! Flag[i])Data[MIN[i]] = - 1 ;for(LL i = 1; i <= N; i ++){if(Data[i] == -1) continue ;Finally[++ All] = - Data[i] ;}nth_element(Finally + 1, Finally + K + 1, Finally + All + 1) ;/*由于我們只需要知道前K個(gè)數(shù)而并不需要知道具體順序,所以可以直接使用STL里面的nth_element而不用sort*/for(LL i = 1; i <= K; i ++)Ans += - Finally[i] ;//點(diǎn)權(quán)是存的相反數(shù),好用nth_elementprintf("%lld", Ans) ;return 0 ; }

    轉(zhuǎn)載于:https://www.cnblogs.com/Yeasio-Nein/p/Samsara.html

    總結(jié)

    以上是生活随笔為你收集整理的$Self~Problem~C~:~Samsara$的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。