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
  • 相关阅读:
    Input file 调用相机
    C#读取txt文件
    高并发下获取随机字符串
    将Datatable转换为Json数据
    System.IO.Path 获得文件的后缀名
    用Js写的贪吃蛇游戏
    C#中的事件
    通过一个控制台小Demo--算术题,来展示C#基本的程序结构
    数据库高级应用之游标
    数据库高级应用之事务
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4811208.html
Copyright © 2011-2022 走看看