1. 程式人生 > 實用技巧 >Codeforces Round #660 (Div. 2) Captain Flint and Treasure 拓撲排序(按照出度、入讀兩邊拓撲排序)

Codeforces Round #660 (Div. 2) Captain Flint and Treasure 拓撲排序(按照出度、入讀兩邊拓撲排序)

題目連結:Captain Flint and Treasure

題意:

一種操作為 選一個下標 使得ans+=a[i] 且 把a[b[i]]+a[i] 要求每個下標都進行一種這樣的操作,問怎麼樣的操作順序才能使得ans最大

題解:

在題目面板的輸入裡面說了這是一個有向無環圖,我怎麼沒看到題目上說這是一個圖?

我們可以把那個操作當作一條邊,而且那個操作還是單向的,所以就成有向無環圖了

如果a[i]>=0,那麼肯定需要進行這種操作(因為會增加ans的值)。如果a[i]為負數,那麼肯定是儘量減少這種操作

那麼對於a[i]>=0的數,我們對入度為0的點進行拓撲排序,以使得a[i]儘可能的為最後的答案ans做貢獻

對於a[i]<0的數,那麼就從出度為0的點開始進行拓撲排序

程式碼:

  1 #include<stack>
  2 #include<queue>
  3 #include<map>
  4 #include<cstdio>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 #include<vector>
  9 #define fi first
 10 #define se second
 11
#define pb push_back 12 using namespace std; 13 typedef long long ll; 14 const int maxn=2e5+10; 15 const int mod=1e9+7; 16 const double eps=1e-8; 17 ll a[maxn]; 18 ll b[maxn]; 19 ll ru[maxn]; 20 ll chu[maxn]; 21 vector<ll>E[maxn]; 22 vector<ll>G[maxn]; 23 ll vis[maxn]; 24 int
main() 25 { 26 ios::sync_with_stdio(false); 27 cin.tie(0); 28 ll n; 29 cin>>n; 30 ll sum=0; 31 for(ll i=1;i<=n;i++) 32 { 33 cin>>a[i]; 34 } 35 for(ll i=1;i<=n;i++) 36 { 37 cin>>b[i]; 38 } 39 vector<ll>ans; 40 for(ll i=1;i<=n;i++) 41 { 42 if(b[i]==-1) 43 continue; 44 ru[b[i]]++; 45 chu[i]++; 46 E[i].pb(b[i]); //存放正向邊的vector 47 G[b[i]].pb(i); //存放逆向邊的vector 48 } 49 queue<ll>q; 50 for(ll i=1;i<=n;i++) //找出入度為0的點,並從此開始進行拓撲排序 51 { 52 if(ru[i]==0) //而且我們只處理ai值大於0的點 53 { 54 q.push(i); 55 } 56 } 57 while(!q.empty()) 58 { 59 ll u=q.front(); 60 q.pop(); 61 for(auto &v:E[u]) 62 { 63 ru[v]--; 64 if(a[u]>=0) //根據題目描述一個點i指向下一個點b[i],那麼這個邊只會有一條,所以u這個點雖然在for迴圈 65 { //內,但是這個迴圈只會迴圈一次 66 a[v]+=a[u]; 67 sum+=a[u]; 68 ans.pb(u); //ans存放路徑,因為最後要輸出 69 vis[u]=1; 70 } 71 if(ru[v]==0) 72 { 73 q.push(v); 74 } 75 } 76 } 77 queue<ll>r; 78 for(ll i=1;i<=n;i++) 79 { 80 if(chu[i]==0&&vis[i]==0) 81 { 82 r.push(i); 83 } 84 } 85 while(!r.empty()) 86 { 87 ll u=r.front(); 88 r.pop(); 89 if(vis[u]==0) 90 { 91 sum+=a[u]; 92 ans.pb(u); 93 } 94 for(auto &v:G[u]) 95 { 96 chu[v]--; 97 if(chu[v]==0) 98 r.push(v); 99 } 100 } 101 printf("%lld\n",sum); 102 ll len=ans.size(); 103 for(ll i=0;i<len;++i) 104 { 105 // if(i==len-1) 106 // printf("%lld\n",ans[i]); 107 // else 108 printf("%lld ",ans[i]); 109 } 110 return 0; 111 }