zoukankan      html  css  js  c++  java
  • BZOJ 4349: 最小树形图

    Description

    (n)个节点,每个节点有一个攻击代价和需要攻击的次数。

    有(k)个关系,攻击(x)后,(y)的攻击代价变成(z)。

    Solution

    朱刘算法。

    这个好像就是求什么最小树形图的东东...

    最小树形图跟最小生成树差不多,不过最小生成树是无向图,最小树形图是有向图,让一个节点和其他节点联通的最小代价。

    这个建模也非常容易,只需要确定第一次的攻击即可,之后的一定都以最小代价攻击。

    朱刘算法也很简单,步骤就是

    找到每个节点的最小入边。

    统计答案。

    找环,缩环,把边权设成原边权-最小入边边权。

    Code

    /**************************************************************
        Problem: 2260
        User: BeiYu
        Language: C++
        Result: Accepted
        Time:8 ms
        Memory:1340 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
     
    inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
     
    const int N = 55;
    const int M = N*N+50;
     
    struct Edge { int fr,to;double v; };
    Edge edge[M];
     
    int n,m,rt;
    int b[N];
    double mic[N];
    double miv[N];
    int pre[N],vis[N],id[N];
     
    void AddEdge(int fr,int to,double v) { edge[++m]=(Edge){ fr,to,v }; }
     
    double Solve(int n) {
        double res=0;
        for(int cnt,tmp;;) {
            for(int i=1;i<=n;i++) miv[i]=1e9,pre[i]=0;
            for(int i=1;i<=m;i++) {
                Edge &e=edge[i];
                if(e.v<miv[e.to]) miv[e.to]=e.v,pre[e.to]=e.fr;
            }
            for(int i=1;i<=n;i++) if(pre[i]) res+=miv[i];
            memset(vis,0,sizeof(vis));
            memset(id,0,sizeof(id));
            vis[0]=tmp=1,cnt=0;
            for(int i=1;i<=n;i++) if(!vis[i]) {
                ++tmp;int u=i;
                for(;!vis[u];u=pre[u]) vis[u]=tmp;
                if(vis[u]==tmp) {
                    ++cnt;
                    for(;!id[u];u=pre[u]) id[u]=cnt;
                }
            }
            if(!cnt) break;
            for(int i=1;i<=n;i++) if(!id[i]) id[i]=++cnt;
            int mm=m;m=0;
            for(int i=1;i<=mm;i++) {
                Edge &e=edge[i];
                if(id[e.fr]!=id[e.to]) AddEdge(id[e.fr],id[e.to],e.v-miv[e.to]);
            }
            n=cnt;
        }return res;
    }
     
    int main() {
        n=in(),rt=n+1;
        for(int i=1;i<=n;i++) {
            double x;scanf("%lf",&x);
            mic[i]=x;
            b[i]=in();
            if(b[i]) AddEdge(rt,i,x);
        }
        for(int k=in();k--;) {
            int x=in(),y=in();
            double z;scanf("%lf",&z);
            if(b[x] && b[y]) {
                AddEdge(x,y,z);
                mic[y]=min(mic[y],z);
            }
        }
        double ans=Solve(n+1);
    //  cout<<ans<<endl;
    //  for(int i=1;i<=n;i++) cout<<mic[i]<<" ";cout<<endl;
        for(int i=1;i<=n;i++) if(b[i]) ans+=(b[i]-1)*mic[i];
        printf("%.2lf
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    HashMap源码学习
    java线程池
    MySQL的MVCC
    volatile关键字学习
    ArrayList, Vector和CopyOnWriteArrayList对比学习
    曹工说Redis源码(3)-- redis server 启动过程完整解析(中)
    曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充
    曹工杂谈:我们的应用,启动就要去其他服务拉数据,那其他服务挂了,我们就起不来了?
    程序员正确的提问方式(个人建议)
    曹工说Redis源码(1)-- redis debug环境搭建,使用clion,达到和调试java一样的效果
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6598524.html
Copyright © 2011-2022 走看看