• Selling a Menagerie(cf)


    该题考察了拓扑排序+dfs

    题意:你是一个动物园的主人,该动物园由编号从1到n的n只动物组成。然而,维护动物园是相当昂贵的,所以你决定卖掉它!众所周知,每种动物都害怕另一种动物。更确切地说,动物ii害怕动物ai(ai≠i)。此外,每只动物的成本是已知的,对于动物ii,它等于ci。你会按照固定的顺序卖掉你所有的动物。形式上,您需要选择一些排列†p1,p2,…,pn,然后先出售动物p1,然后出售动物p2,依此类推,最后出售动物pn。当你出售动物ii时

    有两种可能的结果:如果动物ai在动物ii之前出售,你将因出售动物ii而获得cici资金。如果动物ai在动物i之前没有被出售,您出售动物i将获得2∙ci的金钱。(令人惊讶的是,目前害怕的动物更有价值)。你的任务是选择出售动物的顺序,以最大限度地提高总利润。多组输入

    输入样例

    8

    3

    2 3 2

    6 6 1

    8

    2 1 4 3 6 5 8 7

    1 2 1 2 2 1 2 1

    5

    2 1 1 1 1

    9 8 1 1 1

    2

    2 1

    1000000000 999999999

    7

    2 3 2 6 4 4 3

    1 2 3 4 5 6 7

    5

    3 4 4 1 3

    3 4 5 6 7

    3

    2 1 1

    1 2 2

    4

    2 1 4 1

    1 1 1 1

    输出样例 

    1 2 3
    2 4 5 1 6 3 7 8
    3 4 5 1 2
    1 2
    7 5 1 3 2 6 4
    5 3 2 4 1
    3 2 1
    3 4 1 2
    

    思路: 如果该动物害怕的动物已经卖出了 则该动物能获得利润ci 若没有卖出则ci

    所以应该尽量让每个动物在它害怕的动物卖出前卖出 即 i在a[i]之前卖出(害怕的动物先卖出)

    若该动物没有被任何动物害怕 可以让它们先卖出

    同时将这些动物卖出之后,可能又会使得一些动物不被任何动物害怕(可以想象到用拓扑排序)

     比如 a :2 3 4 5 3,那么动物 1 就没有被任何动物害怕,我们先将它卖出,卖出之后又会使得动物 2 不被任何动物害怕。这个过程可以用拓扑排序实现,相当于连一条 i 到 a[i] 的边,同时记录每个点的入度,入度为 0 时入队即可。

    但这个拓扑过程可能并不会包含所有的点,因为有些点之间可能是一个环的关系,就是一个怕一个,形成了个闭环,比如上述例子中的动物 ,,3,4,5 。对于这种环我们拓扑肯定是处理不了的。我们需要考虑打破这个环,使其成为一个有顺序的链,那么很明显我们可以使价格最便宜的动物作为链的末尾,因此我们可以先用一个 dfs 找到这个环中价格最小的动物,然后让它所害怕的动物作为链的起始即可。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. using namespace std;
    7. const int N=5e5+10;
    8. int a[N],c[N],d[N],id=-1,mins=0;
    9. bool st[N];
    10. void dfs(int u)
    11. {
    12. if(st[u]) return ;
    13. st[u]=true;
    14. int x=a[u];
    15. if(c[x]
    16. dfs(x);
    17. }
    18. int main()
    19. {
    20. int t;cin>>t;
    21. while(t--)
    22. {
    23. memset(st,0,sizeof st);
    24. memset(d,0,sizeof d);
    25. int n;cin>>n;
    26. for(int i=1;i<=n;i++) cin>>a[i],d[a[i]]++;
    27. for(int i=1;i<=n;i++) cin>>c[i];
    28. queue<int>q;
    29. vector<int>v;
    30. //拓扑排序
    31. for(int i=1;i<=n;i++)
    32. if(!d[i]) q.push(i);
    33. while(q.size())
    34. {
    35. int t=q.front();
    36. q.pop();
    37. st[t]=true;
    38. v.push_back(t);
    39. int x=a[t];
    40. d[x]--;
    41. if(!d[x]) q.push(x);
    42. }
    43. for(int i=1;i<=n;i++)
    44. {
    45. //寻找是否有环
    46. if(!st[i])
    47. {
    48. mins=c[i];
    49. id=i;
    50. dfs(i);
    51. int x=a[id];、
    52. //用do while 先运行一次 否则用while根本就不会进去
    53. do
    54. {
    55. v.push_back(x);
    56. x=a[x];
    57. }while(x!=a[id]);
    58. }
    59. }
    60. for(int i=0;isize();i++) cout<" ";
    61. cout<
    62. }
    63. return 0;
    64. }

  • 相关阅读:
    [附源码]java毕业设计逸尘房屋销售管理系统
    Python-算法编程100例-滑动窗口(入门级)
    matlab解下列微分方程
    docker安装和使用
    那些年遇到过的问题与解决方案
    C语言编程题(五)sizeof结构体与字节对齐
    Go如何优雅的记录操作日志
    LeetCode_动态规划_中等_764.最大加号标志
    redis主从同步
    教程六 在Go中使用Energy创建跨平台GUI - 应用下载事件
  • 原文地址:https://blog.csdn.net/m0_74015873/article/details/132776664