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 }
标签:排序,const,拓扑,Treasure,maxn,ans,操作,include,ll 来源: https://www.cnblogs.com/kongbursi-2292702937/p/13518856.html