• F. Selling a Menagerie Codeforces Round 895 (Div. 3)


    Problem - F - Codeforces

    题目大意:有n个动物,每个动物i有一个害怕的动物a[i],现要卖掉所有动物,每个动物都有价值c[i],如果i在a[i]之前卖掉,就会获得2*c[i]的价值,如果在a[i]之后被卖掉就会获得c[i]的价值,问以什么顺序卖掉所有动物能使获得的总价值最高

    2<=n<=1e5;1<=ci<=1e9

    思路:对于这种约束问题,首先直接从i向a[i]建单向边,初始状态下,所有没有入边的点卖掉都能获得2*c[i]的价值,同时因为该点被删除,所以他们指向的点入度-1,接着卖掉入度为0的点,依次循环,最后一定会出现剩下的点都成环的情况。

    对于某一个环,我们最优的方案就是选择一个点留着最后卖,其余的点按照环的方向依次卖,例如题目中的样例5,画出的涂如下,卖的顺序就是1,5,7,3,2,6,4

    也就是我们dfs遍历每个环,在环中找出价值最小的那个点,把它放在最后,其余点按环的顺序即可

    1. //#include<__msvc_all_public_headers.hpp>
    2. #include
    3. using namespace std;
    4. const int N = 1e5 + 5;
    5. typedef long long ll;
    6. int n;
    7. paira[N];
    8. int to[N];
    9. int d[N];
    10. bool vis[N];
    11. ll c[N];
    12. void init()
    13. {
    14. for (int i = 1; i <= n; i++)
    15. {
    16. d[i] = 0;
    17. vis[i] = 0;
    18. }
    19. }
    20. ll mi, mii;
    21. void dfs(int u)
    22. {//遍历环
    23. int v = to[u];
    24. if (c[u] < mi)
    25. {
    26. mi = c[u];
    27. mii = u;
    28. }//找到环中价值最小的点
    29. vis[u] = 1;
    30. if (!vis[v])
    31. {
    32. dfs(v);
    33. }
    34. }
    35. void solve()
    36. {
    37. cin >> n;
    38. init();
    39. for (int i = 1; i <= n; i++)
    40. {
    41. int v;
    42. cin >> v;
    43. to[i] = v;//建有向边
    44. d[v]++;//记录入度
    45. }
    46. for (int i = 1; i <= n; i++)
    47. {
    48. cin >> c[i];
    49. }
    50. queue<int>q;
    51. vector<int>ans;
    52. for (int i = 1; i <= n; i++)
    53. {
    54. if (d[i] == 0)
    55. {//将初始入度为0的先卖掉
    56. q.push(i);
    57. vis[i] = 1;
    58. }
    59. }
    60. while (!q.empty())
    61. {//先处理环外的点
    62. int u = q.front();
    63. q.pop();
    64. ans.push_back(u);
    65. int v = to[u];
    66. d[v]--;//类似于拓扑排序的操作
    67. if (!d[v])
    68. {
    69. vis[v] = 1;
    70. q.push(v);
    71. }
    72. }
    73. for (int i = 1; i <= n; i++)
    74. {
    75. if (!vis[i])
    76. {
    77. mi = 1e9 + 1;
    78. dfs(i);
    79. int now = to[mii];//从价值最小的点的下一个点开始沿着环卖
    80. while (now != mii)
    81. {
    82. ans.push_back(now);
    83. now = to[now];
    84. }
    85. ans.push_back(mii);
    86. }
    87. }
    88. for (int i = 0; i < ans.size(); i++)
    89. {
    90. cout << ans[i] << " ";
    91. }
    92. cout << endl;
    93. }
    94. int main()
    95. {
    96. ios::sync_with_stdio(false);
    97. cin.tie(0);
    98. int t;
    99. cin >> t;
    100. while (t--)
    101. {
    102. solve();
    103. }
    104. }

  • 相关阅读:
    如何从 SD 卡恢复已删除文件?值得尝试的 10 款 SD 卡恢复软件解决方案
    [前端开发] 前端工程代码规范 Husky + Commitlint + Prettier + Eslint + Stylelint
    Java包装类和泛型
    [LeetCode 687]最长同值路径
    普通jar和SpringBootjar的区别
    Linux之内核Platform LED
    Ubuntu上的论文翻译软件 --- 兰译
    计算机组成原理_Cache写策略
    【从零开始学习Redis | 第一篇】快速了解Redis
    SpringBoot整合RabbitMQ实现消息的发送与接收,确认消息,延时消息
  • 原文地址:https://blog.csdn.net/ashbringer233/article/details/132756134