zoukankan      html  css  js  c++  java
  • 通讯(tarjan缩点)(20190716NOIP模拟测试4)

    B. 通讯

     
    题目类型:传统 评测方式:文本比较
     内存限制:256 MiB 时间限制:1000 ms 标准输入输出

    题目描述

    “这一切都是命运石之门的选择。”

    试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短 信,并由此得知了伦太郎制作出了电话微波炉(仮)。

    为了掌握时间机器的技术,SERN总部必须尽快将这个消息通过地下秘密通讯 网络,传达到所有分部。

    SERN共有N个部门(总部编号为0),通讯网络有M条单向通讯线路,每条线 路有一个固定的通讯花费Ci。

    为了保密,消息的传递只能按照固定的方式进行:从一个已知消息的部门向 另一个与它有线路的部门传递(可能存在多条通信线路)。我们定义总费用为所 有部门传递消息的费用和。

    幸运的是,如果两个部门可以直接或间接地相互传递消息(即能按照上述方 法将信息由X传递到Y,同时能由Y传递到X),我们就可以忽略它们之间的花费。

    由于资金问题(预算都花在粒子对撞机上了),SERN总部的工程师希望知道, 达到目标的最小花费是多少。

    输入格式

    多组数据,文件以2个0结尾。

    每组数据第一行,一个整数N,表示有N个包括总部的部门(从0开始编号)。 然后是一个整数M,表示有M条单向通讯线路。

    接下来M行,每行三个整数,Xi,Yi,Ci,表示第i条线路从Xi连向Yi,花费为 Ci。

    输出格式

    每组数据一行,一个整数表示达到目标的最小花费。

    样例

    样例输入

    3 3
    0 1 100
    1 2 50
    0 2 100
    3 3
    0 1 100
    1 2 50
    2 1 100
    2 2
    0 1 50
    0 1 100
    0 0

    样例输出

    150
    100
    50

    数据范围与提示

    样例解释

    第一组数据:总部把消息传给分部1,分部1再传给分部2.总费用:100+50=150.

    第二组数据:总部把消息传给分部1,由于分部1和分部2可以互相传递消息,所以分部1可以无费用把消息传给2.总费用:100+0=100.

    第三组数据:总部把消息传给分部1,最小费用为50.总费用:50.

    数据范围

    对于10%的数据,保证M=N-1

    对于另30%的数据,N ≤ 20 ,M ≤ 20

    对于100%的数据,N ≤ 50000 ,M ≤ 10^5 ,Ci ≤ 10^5 ,

    数据组数 ≤ 5
    数据保证一定可以将信息传递到所有部门。

    水题

    tarjan缩点,贪心找每个点的最小入边即可(我用dfs实现,本质都是贪心)

    我的tarjan+dfs(下面有天皇skyh的贪心找小边)

    #include<iostream>
    #include<cstdio>
    #include<vector>
    using namespace std;
    int n,m,dfn[51000],low[51000],num,st[51000],sp[51000],ins[51000],mi[51000],v[51000],cnt;
    struct node{
        int ver,len;
    };
    vector<node>to[51000],son[51000];
    void tarjan(int x){
        dfn[x]=low[x]=++num;
        st[++st[0]]=x;
        ins[x]=1;
        //sort(to[x].begin(),to[x].end(),cmp);
        for(int i=0;i<to[x].size();i++){
            node w=to[x][i];
            if(!dfn[w.ver]){
                tarjan(w.ver);
                low[x]=min(low[x],low[w.ver]);
            }
            else if(ins[w.ver]) low[x]=min(low[x],dfn[w.ver]);
        }
        if(low[x]==dfn[x]){
            cnt++;
            int y;
            do{
                y=st[st[0]--];
                ins[y]=0;
                sp[y]=cnt;
            }while(y!=x);
    
        }
    }
    long long dfs(int x){
        v[x]=1;
        long long cet=0;
        //sort(son[x].begin(),son[x].end(),cmp);
    //    cout<<x<<" "<<son[x].size()<<endl;
        for(int i=0;i<son[x].size();i++){
            node w=son[x][i];
            //cout<<w.ver<<" "<<w.len<<endl;
            if(v[w.ver]){
                if(mi[w.ver]>w.len){
                    cet-=(mi[w.ver]-w.len);
                    mi[w.ver]=w.len;
                }
                continue;
            }
            cet+=dfs(w.ver);
            cet+=w.len;
            
            mi[w.ver]=w.len;
        }
        ///cout<<cet<<endl;
        return cet;
        
    }
    int main(){
        scanf("%d%d",&n,&m);
        while(n!=0||m!=0){
            int x;
            for(int i=1;i<=m;i++){
                node w;
                scanf("%d%d%d",&x,&w.ver,&w.len);
                w.ver++;
                to[x+1].push_back(w);
            }
        //    for(int i=1;i<=n;i++) cout<<i<<" "<<to[i].size()<<endl;
            for(int i=1;i<=n;i++)
                if(!dfn[i]) tarjan(i);
            //for(int i=1;i<=n;i++) cout<<i<<" "<<to[i].size()<<endl;
            for(int i=1;i<=n;i++){
                //cout<<i<<" "<<sp[i]<<" "<<to[i].size()<<endl;
                for(int j=0;j<to[i].size();j++){
                    node w=to[i][j];
                    if(sp[i]!=sp[w.ver]){
                        w.ver=sp[w.ver];
                        son[sp[i]].push_back(w);
                    }
                }
            }
            /*for(int i=1;i<=cnt;i++){
                cout<<i<<" "<<son[i].size()<<endl;
                for(int j=0;j<son[i].size();j++){
                    printf("%d %d %d
    ",i,son[i][j].ver,son[i][j].len);
                }
            }*/
            long long ans=dfs(sp[1]);    
            printf("%lld
    ",ans);
            for(int i=1;i<=n;i++){
                dfn[i]=low[i]=v[i]=sp[i]=mi[i]=v[i]=0;
                to[i].clear();
                son[i].clear();
                num=0;
                cnt=0;
            }
            scanf("%d%d",&n,&m);
        }
        
    }

    ——————————————————————————————————————————————————————————————————————————————

    天皇skyh的贪心找小边

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define db(x) cerr<<#x<<"="<<x<<endl
    #define cl(x) memset(x,0,sizeof(x))
    using namespace std;
    const int N=50100,M=501000;
    int n,m,scc;
    int tot,head[N],to[M],nxt[M],w[M];
    int top,stack[N],dfn[N],low[N],num,bl[N];
    bool instack[N];
    int imin[N];
    void tarjan(int x)
    {
        dfn[x]=low[x]=++num;
        stack[++top]=x; instack[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i];
            if(!dfn[y])
            {
                tarjan(y);
                low[x]=min(low[x],low[y]);
            }
            else if(instack[y]) low[x]=min(low[x],dfn[y]);
        }
        if(dfn[x]==low[x])
        {
            ++scc; int y;
            do{
                y=stack[top--];
                bl[y]=scc;
                instack[y]=0;
            }while(y!=x);
        }
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)==2&&(n||m))
        {
            cl(dfn); cl(head);
            memset(imin,0x3f,sizeof(imin));
            tot=0; top=0; num=0; scc=0;
            for(int i=1,a,b,d;i<=m;i++)
            {
                scanf("%d%d%d",&a,&b,&d);
                a++; b++;
                to[++tot]=b; w[tot]=d;
                nxt[tot]=head[a]; head[a]=tot;
            }
            tarjan(1);
            //db(scc);
            for(int i=1;i<=n;i++)
                for(int j=head[i];j;j=nxt[j])
                {
                    int y=to[j];
                    if(bl[i]==bl[y]) continue;
                    imin[bl[y]]=min(imin[bl[y]],w[j]);
                }
            long long ans=0;
            for(int i=1;i<=scc;i++)
                if(imin[i]<=10000000)
                    ans+=imin[i];
            printf("%lld
    ",ans);
        }
        return 0;
    }
    $Will$ $Be$ $The$ $King$
  • 相关阅读:
    javascript中的复制
    使用tensorflow-serving部署tensorflow模型
    Linux端口命令
    intellij idea强制更新索引
    The minimum required Cuda capability is 3.7.
    tensorflow没有代码提示的问题
    何为学术能力
    PageRank算法
    keras的训练引擎:train_array.py和train_generator.py
    如何阅读源代码
  • 原文地址:https://www.cnblogs.com/heoitys/p/11199054.html
Copyright © 2011-2022 走看看