zoukankan      html  css  js  c++  java
  • hdu3072 强连通+最小树形图

    题意:有一个人他要把一个消息通知到所有人,已知一些通知关系:A 能通知 B,需要花费 v,而又知道,如果某一个小团体,其中的成员相互都能直接或间接通知到,那么他们之间的消息传递是不需要花费的,现在问这个人将消息传给所有人所需的最小花费。

    首先,一个团体中能够相互通知其实就是一个强连通分量,所以首先找出所有强连通分量,因为内部不需要花费,所以他们就相当于一个点,而早缩点之后,我们就得到了一张有向无环图,消息传递的最小花费其实就是最小树形图的边权和。刚做这个题的时候我还只是看见过最小树形图是什么,做到了我就自己YY了一种做法,就是从每个点拓展,用优先队列存可以拓展的边,取最小边看能否合并还不在树上的点,合并一个点就把它的所有出边再入优先队列。后来WA了我自己也举出反例,就去学习了一下最小树形图的朱刘算法,然后A掉了。

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stack>
      4 #include<queue>
      5 #include<algorithm>
      6 using namespace std;
      7 typedef long long ll;
      8 
      9 const int maxn=5e4+5;
     10 const int maxm=1e5+5;
     11 const int INF=0x3f3f3f3f;
     12 
     13 int head[maxn],point[maxm],nxt[maxm],size,val[maxm];
     14 int n,t,scccnt;
     15 int stx[maxn],low[maxn],scc[maxn],vis[maxn];
     16 int from[maxm],to[maxm],cost[maxm],cntm;
     17 int pre[maxn],id[maxn],in[maxn];
     18 stack<int>S;
     19 
     20 void init(){
     21     memset(head,-1,sizeof(head));
     22     size=cntm=0;
     23     memset(vis,0,sizeof(vis));
     24 }
     25 
     26 void add_mdst(int a,int b,int v){
     27     from[cntm]=a;
     28     to[cntm]=b;
     29     cost[cntm++]=v;
     30 }
     31 
     32 ll mdst(int s,int n){
     33     ll ans=0;
     34     int u,v;
     35     while(1){
     36         memset(in,0x3f,sizeof(in));
     37         for(int i=0;i<cntm;++i){
     38             if(from[i]!=to[i]&&cost[i]<in[to[i]]){
     39                 pre[to[i]]=from[i];
     40                 in[to[i]]=cost[i];
     41             }
     42         }
     43         for(int i=1;i<=n;++i){
     44             if(i!=s&&in[i]==INF){
     45                 return -1;
     46             }
     47         }
     48         int cnt=0;
     49         memset(id,-1,sizeof(id));
     50         memset(vis,-1,sizeof(vis));
     51         in[s]=0;
     52         for(int i=1;i<=n;++i){
     53             ans+=in[i];
     54             v=i;
     55             while(vis[v]!=i&&id[v]==-1&&v!=s){
     56                 vis[v]=i;
     57                 v=pre[v];
     58             }
     59             if(v!=s&&id[v]==-1){
     60                 ++cnt;
     61                 for(u=pre[v];u!=v;u=pre[u])id[u]=cnt;
     62                 id[v]=cnt;
     63             }
     64         }
     65         if(!cnt)break;
     66         for(int i=1;i<=n;++i){
     67             if(id[i]==-1)id[i]=++cnt;
     68         }
     69         for(int i=0;i<cntm;){
     70             v=to[i];
     71             from[i]=id[from[i]];
     72             to[i]=id[to[i]];
     73             if(from[i]!=to[i])cost[i++]-=in[v];
     74             else{
     75                 --cntm;
     76                 cost[i]=cost[cntm];
     77                 to[i]=to[cntm];
     78                 from[i]=from[cntm];
     79             }
     80         }
     81         n=cnt;
     82         s=id[s];
     83     }
     84     return ans;
     85 }
     86 
     87 void add(int a,int b,int v){
     88     point[size]=b;
     89     val[size]=v;
     90     nxt[size]=head[a];
     91     head[a]=size++;
     92 }
     93 
     94 void dfs(int s){
     95     stx[s]=low[s]=++t;
     96     S.push(s);
     97     for(int i=head[s];~i;i=nxt[i]){
     98         int j=point[i];
     99         if(!stx[j]){
    100             dfs(j);
    101             low[s]=min(low[s],low[j]);
    102         }
    103         else if(!scc[j]){
    104             low[s]=min(low[s],stx[j]);
    105         }
    106     }
    107     if(low[s]==stx[s]){
    108         scccnt++;
    109         while(1){
    110             int u=S.top();S.pop();
    111             scc[u]=scccnt;
    112             if(s==u)break;
    113         }
    114     }
    115 }
    116 
    117 void setscc(){
    118     memset(stx,0,sizeof(stx));
    119     memset(scc,0,sizeof(scc));
    120     t=scccnt=0;
    121     for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
    122     for(int i=1;i<=n;++i){
    123         for(int j=head[i];~j;j=nxt[j]){
    124             int k=point[j];
    125             if(scc[i]!=scc[k]){
    126                 add_mdst(scc[i],scc[k],val[j]);
    127             }
    128         }
    129     }
    130 }
    131 
    132 int main(){
    133     int m;
    134     while(scanf("%d%d",&n,&m)!=EOF){
    135         init();
    136         while(m--){
    137             int a,b,v;
    138             scanf("%d%d%d",&a,&b,&v);
    139             add(a+1,b+1,v);
    140         }
    141         setscc();
    142         ll ans=0;
    143         int pre=scc[1];
    144         printf("%I64d
    ",mdst(pre,scccnt));
    145     }
    146     return 0;
    147 }
    View Code
  • 相关阅读:
    Palindrome Partitioning
    Minimum Path Sum
    Maximum Depth of Binary Tree
    Minimum Depth of Binary Tree
    Unique Binary Search Trees II
    Unique Binary Search Trees
    Merge Intervals
    Merge Sorted Array
    Unique Paths II
    C++ Primer Plus 笔记第九章
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4811208.html
Copyright © 2011-2022 走看看