zoukankan      html  css  js  c++  java
  • [HDU3072]:Intelligence System(塔尖+贪心)

    题目传送门


    题目描述

    “这一切都是命运石之门的选择。”
    试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短 信,并由此得知了伦太郎制作出了电话微波炉(仮)。
    为了掌握时间机器的技术,SERN总部必须尽快将这个消息通过地下秘密通讯 网络,传达到所有分部。
    SERN共有N个部门(总部编号为0),通讯网络有M条单向通讯线路,每条线 路有一个固定的通讯花费$C_i$
    为了保密,消息的传递只能按照固定的方式进行:从一个已知消息的部门向 另一个与它有线路的部门传递(可能存在多条通信线路)。我们定义总费用为所 有部门传递消息的费用和。
    幸运的是,如果两个部门可以直接或间接地相互传递消息(即能按照上述方法将信息由X传递到Y,同时能由Y传递到X),我们就可以忽略它们之间的花费。
    由于资金问题(预算都花在粒子对撞机上了),SERN总部的工程师希望知道, 达到目标的最小花费是多少。


    输入格式

    多组数据,文件以20结尾。
    每组数据第一行,一个整数N,表示有N个包括总部的部门(从0开始编号)。 然后是一个整数M,表示有M条单向通讯线路。
    接下来M行,每行三个整数$X_i$,$Y_i$,$C_i$,表示第i条线路从$X_i$连向$Y_i$,花费为$C_i$


    输出格式

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


    样例

    样例输入:

    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≤20M≤20
    对于100%的数据,N≤50000M≤105$C_i$≤105,数据组数≤5
    数据保证一定可以将信息传递到所有部门。


    题解

    不知道你有没有注意到这句话:

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

    这意味着什么呢?

    就是说,在一个强联通分量里,任意两点之间相互到达的花费为0,那么直接一个塔尖缩点刚上去就好了。

    那么缩完点之后要怎么计算答案呢?

    考虑这样一个问题,贪心思想,我们要从根节点到达所有点,每一个点被到达一次即可,那么我们就找所有能到达这个点中权值最小的那个边,走它就好了。

    枚举所有的边,找非强联通分量里的边,不断更新这条边的to的最小值即可。

    模板一定要打对!!!


    代码时刻

    本题代码:

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int nxt;
    	int to;
    	int w;
    }e[100010];//存边
    int n,m;
    int head[50010],cnt;
    int dfn[50010],low[50010],sta[50010],ins[50010],c[50010],num,top,tot;//塔尖
    int ans;//存储答案
    int fl[50010];//存储最小的那个边
    void pre_work()//多测不清空,爆零两行泪TAT……
    {
    	cnt=num=top=tot=0;
    	ans=0;
    	for(int i=1;i<=n;i++)
    		head[i]=dfn[i]=low[i]=ins[i]=c[i]=0;
    	memset(fl,0x3f,sizeof(fl));
    }
    void add(int x,int y,int w)//建边
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	e[cnt].w=w;
    	head[x]=cnt;
    }
    void tarjan(int x)//塔尖求强联通分量
    {
    	dfn[x]=low[x]=++num;
    	sta[++top]=x;
    	ins[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		if(!dfn[e[i].to])
    		{
    			tarjan(e[i].to);
    			low[x]=min(low[x],low[e[i].to]);
    		}
    		else if(ins[e[i].to])
    			low[x]=min(low[x],dfn[e[i].to]);
    	}
    	if(dfn[x]==low[x])
    	{
    		tot++;
    		int y;
    		do
    		{
    			y=sta[top--];
    			ins[y]=0;
    			c[y]=tot;
    		}while(x!=y);
    	}
    }
    int main()
    {
    	memset(fl,0x3f,sizeof(fl));
    	while(1)
    	{
    		scanf("%d%d",&n,&m);
    		if(!n&&!m)break;
    		for(int i=1;i<=m;i++)
    		{
    			int x,y,c;
    			scanf("%d%d%d",&x,&y,&c);
    			add(x+1,y+1,c);
    		}
    		tarjan(1);
    		for(int x=1;x<=n;x++)
    			for(int i=head[x];i;i=e[i].nxt)
    				if(c[x]!=c[e[i].to])
    					fl[c[e[i].to]]=min(fl[c[e[i].to]],e[i].w);//不断更新最小值
    		fl[c[1]]=0;
    		for(int i=1;i<=tot;i++)ans+=fl[i];
    		printf("%d
    ",ans);
    		pre_work();
    	}
    	return 0;
    }
    

    HDU代码(输入格式不同):

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
        int nxt;
        int to;
        int w;
    }e[100010];
    int n,m;
    int head[50010],cnt;
    int dfn[50010],low[50010],sta[50010],ins[50010],c[50010],num,top,tot;
    int ans;
    int fl[50010];
    void pre_work()
    {
        cnt=num=top=tot=0;
        ans=0;
        for(int i=1;i<=n;i++)
            head[i]=dfn[i]=low[i]=ins[i]=c[i]=0;
        memset(fl,0x3f,sizeof(fl));
    }
    void add(int x,int y,int w)
    {
        e[++cnt].nxt=head[x];
        e[cnt].to=y;
        e[cnt].w=w;
        head[x]=cnt;
    }
    void tarjan(int x)
    {
        dfn[x]=low[x]=++num;
        sta[++top]=x;
        ins[x]=1;
        for(int i=head[x];i;i=e[i].nxt)
        {
            if(!dfn[e[i].to])
            {
                tarjan(e[i].to);
                low[x]=min(low[x],low[e[i].to]);
            }
            else if(ins[e[i].to])
                low[x]=min(low[x],dfn[e[i].to]);
        }
        if(dfn[x]==low[x])
        {
            tot++;
            int y;
            do
            {
                y=sta[top--];
                ins[y]=0;
                c[y]=tot;
            }while(x!=y);
        }
    }
    int main()
    {
        memset(fl,0x3f,sizeof(fl));
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=1;i<=m;i++)
            {
                int x,y,c;
                scanf("%d%d%d",&x,&y,&c);
                add(x+1,y+1,c);
            }
            tarjan(1);
            for(int x=1;x<=n;x++)
                for(int i=head[x];i;i=e[i].nxt)
                    if(c[x]!=c[e[i].to])
                        fl[c[e[i].to]]=min(fl[c[e[i].to]],e[i].w);
            fl[c[1]]=0;
            for(int i=1;i<=tot;i++)ans+=fl[i];
            printf("%d
    ",ans);
            pre_work();
        }
        return 0;
    }
    

    rp++

  • 相关阅读:
    Fidder4 顶部提示 “The system proxy was changed,click to reenable fiddler capture”。
    redis 哨兵 sentinel master slave 连接建立过程
    虚拟点赞浏览功能的大数据量测试
    python基础练习题(题目 字母识词)
    python基础练习题(题目 回文数)
    python基础练习题(题目 递归求等差数列)
    python基础练习题(题目 递归输出)
    python基础练习题(题目 递归求阶乘)
    python基础练习题(题目 阶乘求和)
    python基础练习题(题目 斐波那契数列II)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11196134.html
Copyright © 2011-2022 走看看