1. 程式人生 > >【NOIP2016提高A組8.12】通訊

【NOIP2016提高A組8.12】通訊

所在 %d mat sizeof 之間 Go 成了 工程 max

題目

“這一切都是命運石之門的選擇。”
試圖研制時間機器的機關SERN截獲了中二科學家倫太郎發往過去的一條短信,並由此得知了倫太郎制作出了電話微波爐(仮)。
為了掌握時間機器的技術,SERN總部必須盡快將這個消息通過地下秘密通訊網絡,傳達到所有分部。
SERN共有N個部門(總部編號為0),通訊網絡有M條單向通訊線路,每條線路有一個固定的通訊花費Ci。
為了保密,消息的傳遞只能按照固定的方式進行:從一個已知消息的部門向另一個與它有線路的部門傳遞(可能存在多條通信線路)。我們定義總費用為所有部門傳遞消息的費用和。
幸運的是,如果兩個部門可以直接或間接地相互傳遞消息(即能按照上述方法將信息由X傳遞到Y,同時能由Y傳遞到X),我們就可以忽略它們之間的花費。

由於資金問題(預算都花在粒子對撞機上了),SERN總部的工程師希望知道,達到目標的最小花費是多少。

分析

首先處理忽略劃分的情況,如果兩個部門可以直接或間接地相互傳遞消息,那麽他們一定在同一個強連通分量之中。就用tarjan縮點。
所點後就變成了個有向無環圖,
很容易想到,最小花費的方案數選的路線,一定只有n-1條,也就是說每個強連通分量塊的入邊只有一個(除了0所在的強連通分量塊)。
那麽就每個強連通分量塊(除了0所在的強連通分量塊)選一個最小的入邊計入答案。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=50005;
using namespace std;
int next[N*4],last[N*4],to[N*4],v[N*4];
int next1[N*4],last1[N*4],to1[N*4],v1[N*4];
int n,m,tot,dd,d[N],dfn[N],low[N],ddd,part[N],num,ans[N],sum;
bool bz[N];
int bj(int i,int x,int y,int z)
{
    next1[i]=last1[x];
    last1[x]=i;
    to1[i]=y;
    v1[i]=z;
}
int tarjan(int x)
{
    dfn[x]=low[x]=++dd;
    d[++tot]=x;
    bz[x]=false;
    for(int i=last1[x];i;i=next1[i])
    {
        int j=to1[i];
        if(bz[j])
        {
            tarjan(j);
            low[x]=min(low[x],low[j]);
        }
        else
        if(!part[j])
            low[x]=min(low[x],low[j]);
    }
    if(dfn[x]==low[x])
    {
        num++;
        ans[num]=maxlongint;
        while(dfn[d[tot]]>=dfn[x])
        {
            part[d[tot--]]=num;
        }
    }
}
int bj1(int x,int y,int z)
{
    next[++tot]=last[x];
    last[x]=tot;
    to[tot]=y;
    v[tot]=z;   
}
int main()
{
    while(1)
    {
        memset(last,0,sizeof(last));
        memset(last1,0,sizeof(last1));
        memset(part,0,sizeof(part));
        scanf("%d%d",&n,&m);
        if(!n && !m) return 0;
        memset(bz,true,sizeof(bz));
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            bj(i,x,y,z);
        }
        dd=tot=0;
        num=0;
        tarjan(0);
        tot=0;
        sum=0;
        for(int i=0;i<=n-1;i++)
        {
            for(int j=last1[i];j;j=next1[j])
            {
                int k=to1[j];
                bj1(part[i],part[k],v1[j]);
                if(part[i]!=part[k])
                    ans[part[k]]=min(ans[part[k]],v1[j]);
            }
        }
        for(int i=1;i<=num-1;i++)
            sum+=ans[i];
        printf("%d\n",sum);
    }
}

【NOIP2016提高A組8.12】通訊