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++

  • 相关阅读:
    带CheckBox的dojo Tree简单实现,并实现级联选取
    dojox.grid.EnhancedGrid
    Java内存模型及GC原理
    团队任务(第三次)
    团队任务二
    团队任务(一)
    词频统计及其效能分析
    贪吃蛇
    第一课
    软工七组团队2-1作业
  • 原文地址:https://www.cnblogs.com/wzc521/p/11196134.html
Copyright © 2011-2022 走看看