Codeforces Round #660 (Div. 2) Captain Flint and Treasure 拓扑排序(按照出度、入读两边拓扑排序)

题目链接:Captain Flint and Treasure

 

题意:

一种操作为 选一个下标 使得ans+=a[i] 且 把a[b[i]]+a[i]   要求每个下标都进行一种这样的操作,问怎么样的操作顺序才能使得ans最大

 

题解:

在题目面板的输入里面说了这是一个有向无环图,我怎么没看到题目上说这是一个图?

我们可以把那个操作当作一条边,而且那个操作还是单向的,所以就成有向无环图了

Codeforces Round #660 (Div. 2)  Captain Flint and Treasure  拓扑排序(按照出度、入读两边拓扑排序)

 

 

 

如果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 }

 

上一篇:3737. 【NOI2014模拟7.11】挖宝藏(treasure)


下一篇:P2240 【深基12.例1】部分背包问题