• 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
    ",sum);
    102     ll len=ans.size();
    103     for(ll i=0;i<len;++i)
    104     {
    105 //        if(i==len-1)
    106 //            printf("%lld
    ",ans[i]);
    107 //        else
    108             printf("%lld ",ans[i]);
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    链表栈
    双链表
    Linux sar命令查看系统资源使用情况
    Linux 命令(w/who/whoami/who am i)
    shell脚本引用expect
    expect 免交互配置互信
    expect 远程传输文件
    expect 远程执行命令-02
    expect 远程执行命令-01
    expect 脚本自定义变量和位置变量
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13518856.html
Copyright © 2020-2023  润新知