7.16 T2 通讯

题意:以0为起点的一张带权有向图,保证联通,有环的话环里的边权可以忽略,有重边,求从0开始遍历整张图的最小代价。

题解:有环而且可以忽略,tarjan缩点再建新图就可以,然后贪心的从每个点的入边里选一条最小的连上。(其实就考了一个tarjan的模板)

考试的时候一直在想最小生成树,但是最小生成树只适用于无向图,无向图并不适用,反例很好举。结果wa10,直接导致这次考试崩掉,以后一定要注意每种算法的适用条件。

真的很水,考完试5分钟A掉。。。。。。。。考试的时候为什么打不出来呢。。。(想扇自己)

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
struct node
{
    int x,to,nxt,w;
}h[200100];
struct h
{
    int x,to,nxt,w;
}t[200100];
int n,m,rt,mm,top,cnt,num,dfn[50010],low[50010],s[50010],whos[50010],tot,nxt[200100],fa[50010],tet,nx[200100],ans[50010],in[50010];
bool is[50010];
ll as;
int read()
{
    int aa=0,bb=1;char cc=getchar();
    while(cc>'9'||cc<'0'){if(cc=='-') bb=-1;cc=getchar();}
    while(cc<='9'&&cc>='0'){aa=aa*10+cc-'0';cc=getchar();}
    return aa*bb;
}
void init()
{
    top=as=cnt=num=tot=tet=0;
    memset(nxt,0,sizeof(nxt));
    memset(nx,0,sizeof(nx));
    memset(ans,0x5f,sizeof(ans));
    for(int i=1;i<=n;i++){
        dfn[i]=0;low[i]=0;is[i]=0;in[i]=0;
    }
}
int min(int x,int y)
{
    return x<y?x:y;
}
void add(int x,int y,int w)
{
    h[++tot].to=y;
    h[tot].w=w;
    h[tot].nxt=nxt[x];
    nxt[x]=tot;
    h[tot].x=x;
}
void insert(int x,int y,int w)
{
    t[++tet].to=y;
    t[tet].w=w;
    t[tet].nxt=nx[x];
    nx[x]=tet;
    t[tet].x=x;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    s[++top]=x;is[x]=1;
    for(int i=nx[x];i;i=t[i].nxt){
        int y=t[i].to;
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
        }
        else if(is[y]) low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x]){
        num++;
        while(1){
            int tmp=s[top--];
            is[tmp]=0;
            whos[tmp]=num;
            if(tmp==x) break;
        }
    }
}
bool cmp(node a,node b)
{
    return a.w<b.w;
}
void dfs(int x)
{
    for(int i=nxt[x];i;i=h[i].nxt){
        int y=h[i].to;//cout<<h[i].w<<endl;
        ans[y]=min(ans[y],h[i].w);
        dfs(y);
    }
}
int main()
{
    while(1){
        n=read();m=read();
        init();
        if(n==0&&m==0) break;
        int u,v,w;
        for(int i=1;i<=m;i++){
            u=read();v=read();w=read();
            u++,v++;
            insert(u,v,w);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i);
        }
        for(int i=1;i<=n;i++){
            for(int j=nx[i];j;j=t[j].nxt){
                int y=t[j].to;
                if(whos[y]!=whos[i]){
                    add(whos[i],whos[y],t[j].w);
                    in[whos[y]]++;
                }
            }
        }
        for(int i=1;i<=num;i++){
            if(!in[i]){
                rt=i;
                break;
            }
        }
        dfs(rt);ans[rt]=0;
        for(int i=1;i<=num;i++){
            as+=ans[i];
        }
        printf("%lld\n",as);
    }
    return 0;
}
别颓

 

转载于:https://www.cnblogs.com/jrf123/p/11198900.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值