【HDU 3072】【JZOJ 4686】 通讯

来源:互联网 发布:python配置文件怎么写 编辑:程序博客网 时间:2024/05/18 20:06

Description

SERN共有N个部门(总部编号为0),通讯网络有M条单向通讯线路,每条线路有一个固定的通讯花费Ci。
为了保密,消息的传递只能按照固定的方式进行:从一个已知消息的部门向另一个与它有线路的部门传递(可能存在多条通信线路)。我们定义总费用为所有部门传递消息的费用和。
幸运的是,如果两个部门可以直接或间接地相互传递消息(即能按照上述方法将信息由X传递到Y,同时能由Y传递到X),我们就可以忽略它们之间的花费。
由于资金问题(预算都花在粒子对撞机上了),SERN总部的工程师希望知道,达到目标的最小花费是多少。
对于100%的数据,N ≤ 50000 ,M ≤ 10^5 ,Ci ≤ 10^5 ,数据组数 ≤ 5

Analysis

显然什么忽略花费的其实就是一些点处于一个强连通分量内。
那么可以tarjan缩点。
缩点之后大概成了一个DAG上的类MST问题。
我和howarli想到了一个既不能理性证明(意思是可以感性证明)也不能证伪的方法。
类克鲁斯卡尔算法,排序然后把并查集变成一个标记数组。
每连一条有向边就将连到的那个点标记,以后不能再有边连到那里去。(具体看代码)

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define efo(i,v) for(int i=last[v];i;i=next[i])using namespace std;typedef long long ll;const int N=50010,M=200010;int n,m,num,tot,to[M],next[M],wei[M],last[N];int now,top,sta[N],dfn[N],low[N],col[N];bool vis[N],bz[N];struct edge{    int u,v,w;}a[M];bool cmp(edge a,edge b){    return a.u<b.u || a.u==b.u && a.v<b.v ||    a.u==b.u && a.v==b.v && a.w<b.w;}bool cmp2(edge a,edge b){    return a.w<b.w;}void link(int u,int v,int w){    to[++tot]=v,wei[tot]=w,next[tot]=last[u],last[u]=tot;}void tarjan(int v){    sta[++top]=v;    low[v]=dfn[v]=++now;    vis[v]=1;    efo(i,v)    {        int u=to[i];        if(!dfn[u])        {            tarjan(u);            low[v]=min(low[v],low[u]);        }        else        if(vis[u]) low[v]=min(low[v],dfn[u]);    }    if(low[v]==dfn[v])    {        num++;        for(;sta[top+1]!=v;col[sta[top]]=num,vis[sta[top--]]=0);    }}int main(){    for(scanf("%d %d",&n,&m);n || m;scanf("%d %d",&n,&m))    {        now=top=num=tot=0;        memset(last,0,sizeof(last));        fo(i,1,m)        {            scanf("%d %d %d",&a[i].u,&a[i].v,&a[i].w);            a[i].u++,a[i].v++;        }        sort(a+1,a+m+1,cmp);        fo(i,1,m)            if(a[i].u!=a[i-1].u || a[i].v!=a[i-1].v) link(a[i].u,a[i].v,a[i].w);        memset(vis,0,sizeof(vis));        memset(dfn,0,sizeof(dfn));        memset(low,0,sizeof(low));        memset(sta,0,sizeof(sta));        tarjan(1);        fo(i,1,m) a[i].u=col[a[i].u],a[i].v=col[a[i].v];        sort(a+1,a+m+1,cmp2);        int k=0;        ll ans=0;        memset(bz,0,sizeof(bz));        fo(i,1,m)        {            int x=a[i].u,y=a[i].v,w=a[i].w;            if(x==y || bz[y]) continue;            bz[y]=1;            ans+=w;            if(k>=num-1) break;        }        printf("%lld\n",ans);    }    return 0;}
0 0
原创粉丝点击