B. 通讯

 
题目类型:传统 评测方式:文本比较
 内存限制:256 MiB 时间限制:1000 ms 标准输入输出

题目描述

“这一切都是命运石之门的选择。”

试图研制时间机器的机关SERN截获了中二科学家伦太郎发往过去的一条短 信,并由此得知了伦太郎制作出了电话微波炉(仮)。

为了掌握时间机器的技术,SERN总部必须尽快将这个消息通过地下秘密通讯 网络,传达到所有分部。

SERN共有N个部门(总部编号为0),通讯网络有M条单向通讯线路,每条线 路有一个固定的通讯花费Ci。

为了保密,消息的传递只能按照固定的方式进行:从一个已知消息的部门向 另一个与它有线路的部门传递(可能存在多条通信线路)。我们定义总费用为所 有部门传递消息的费用和。

幸运的是,如果两个部门可以直接或间接地相互传递消息(即能按照上述方 法将信息由X传递到Y,同时能由Y传递到X),我们就可以忽略它们之间的花费。

由于资金问题(预算都花在粒子对撞机上了),SERN总部的工程师希望知道, 达到目标的最小花费是多少。

输入格式

多组数据,文件以2个0结尾。

每组数据第一行,一个整数N,表示有N个包括总部的部门(从0开始编号)。 然后是一个整数M,表示有M条单向通讯线路。

接下来M行,每行三个整数,Xi,Yi,Ci,表示第i条线路从Xi连向Yi,花费为 Ci。

输出格式

每组数据一行,一个整数表示达到目标的最小花费。

样例

样例输入

3 3
0 1 100
1 2 50
0 2 100
3 3
0 1 100
1 2 50
2 1 100
2 2
0 1 50
0 1 100
0 0

样例输出

150
100
50

数据范围与提示

样例解释

第一组数据:总部把消息传给分部1,分部1再传给分部2.总费用:100+50=150.

第二组数据:总部把消息传给分部1,由于分部1和分部2可以互相传递消息,所以分部1可以无费用把消息传给2.总费用:100+0=100.

第三组数据:总部把消息传给分部1,最小费用为50.总费用:50.

数据范围

对于10%的数据,保证M=N-1

对于另30%的数据,N ≤ 20 ,M ≤ 20

对于100%的数据,N ≤ 50000 ,M ≤ 10^5 ,Ci ≤ 10^5 ,

数据组数 ≤ 5
数据保证一定可以将信息传递到所有部门。

水题

tarjan缩点,贪心找每个点的最小入边即可(我用dfs实现,本质都是贪心)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 using namespace std;
  5 int n,m,dfn[51000],low[51000],num,st[51000],sp[51000],ins[51000],mi[51000],v[51000],cnt;
  6 struct node{
  7     int ver,len;
  8 };
  9 vector<node>to[51000],son[51000];
 10 void tarjan(int x){
 11     dfn[x]=low[x]=++num;
 12     st[++st[0]]=x;
 13     ins[x]=1;
 14     //sort(to[x].begin(),to[x].end(),cmp);
 15     for(int i=0;i<to[x].size();i++){
 16         node w=to[x][i];
 17         if(!dfn[w.ver]){
 18             tarjan(w.ver);
 19             low[x]=min(low[x],low[w.ver]);
 20         }
 21         else if(ins[w.ver]) low[x]=min(low[x],dfn[w.ver]);
 22     }
 23     if(low[x]==dfn[x]){
 24         cnt++;
 25         int y;
 26         do{
 27             y=st[st[0]--];
 28             ins[y]=0;
 29             sp[y]=cnt;
 30         }while(y!=x);
 31 
 32     }
 33 }
 34 long long dfs(int x){
 35     v[x]=1;
 36     long long cet=0;
 37     //sort(son[x].begin(),son[x].end(),cmp);
 38 //    cout<<x<<" "<<son[x].size()<<endl;
 39     for(int i=0;i<son[x].size();i++){
 40         node w=son[x][i];
 41         //cout<<w.ver<<" "<<w.len<<endl;
 42         if(v[w.ver]){
 43             if(mi[w.ver]>w.len){
 44                 cet-=(mi[w.ver]-w.len);
 45                 mi[w.ver]=w.len;
 46             }
 47             continue;
 48         }
 49         cet+=dfs(w.ver);
 50         cet+=w.len;
 51         
 52         mi[w.ver]=w.len;
 53     }
 54     ///cout<<cet<<endl;
 55     return cet;
 56     
 57 }
 58 int main(){
 59     scanf("%d%d",&n,&m);
 60     while(n!=0||m!=0){
 61         int x;
 62         for(int i=1;i<=m;i++){
 63             node w;
 64             scanf("%d%d%d",&x,&w.ver,&w.len);
 65             w.ver++;
 66             to[x+1].push_back(w);
 67         }
 68     //    for(int i=1;i<=n;i++) cout<<i<<" "<<to[i].size()<<endl;
 69         for(int i=1;i<=n;i++)
 70             if(!dfn[i]) tarjan(i);
 71         //for(int i=1;i<=n;i++) cout<<i<<" "<<to[i].size()<<endl;
 72         for(int i=1;i<=n;i++){
 73             //cout<<i<<" "<<sp[i]<<" "<<to[i].size()<<endl;
 74             for(int j=0;j<to[i].size();j++){
 75                 node w=to[i][j];
 76                 if(sp[i]!=sp[w.ver]){
 77                     w.ver=sp[w.ver];
 78                     son[sp[i]].push_back(w);
 79                 }
 80             }
 81         }
 82         /*for(int i=1;i<=cnt;i++){
 83             cout<<i<<" "<<son[i].size()<<endl;
 84             for(int j=0;j<son[i].size();j++){
 85                 printf("%d %d %d\n",i,son[i][j].ver,son[i][j].len);
 86             }
 87         }*/
 88         long long ans=dfs(sp[1]);    
 89         printf("%lld\n",ans);
 90         for(int i=1;i<=n;i++){
 91             dfn[i]=low[i]=v[i]=sp[i]=mi[i]=v[i]=0;
 92             to[i].clear();
 93             son[i].clear();
 94             num=0;
 95             cnt=0;
 96         }
 97         scanf("%d%d",&n,&m);
 98     }
 99     
100 }

我的tarjan+dfs代码

天皇skyh的贪心找小边

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define db(x) cerr<<#x<<"="<<x<<endl
 5 #define cl(x) memset(x,0,sizeof(x))
 6 using namespace std;
 7 const int N=50100,M=501000;
 8 int n,m,scc;
 9 int tot,head[N],to[M],nxt[M],w[M];
10 int top,stack[N],dfn[N],low[N],num,bl[N];
11 bool instack[N];
12 int imin[N];
13 void tarjan(int x)
14 {
15     dfn[x]=low[x]=++num;
16     stack[++top]=x; instack[x]=1;
17     for(int i=head[x];i;i=nxt[i])
18     {
19         int y=to[i];
20         if(!dfn[y])
21         {
22             tarjan(y);
23             low[x]=min(low[x],low[y]);
24         }
25         else if(instack[y]) low[x]=min(low[x],dfn[y]);
26     }
27     if(dfn[x]==low[x])
28     {
29         ++scc; int y;
30         do{
31             y=stack[top--];
32             bl[y]=scc;
33             instack[y]=0;
34         }while(y!=x);
35     }
36 }
37 int main()
38 {
39     while(scanf("%d%d",&n,&m)==2&&(n||m))
40     {
41         cl(dfn); cl(head);
42         memset(imin,0x3f,sizeof(imin));
43         tot=0; top=0; num=0; scc=0;
44         for(int i=1,a,b,d;i<=m;i++)
45         {
46             scanf("%d%d%d",&a,&b,&d);
47             a++; b++;
48             to[++tot]=b; w[tot]=d;
49             nxt[tot]=head[a]; head[a]=tot;
50         }
51         tarjan(1);
52         //db(scc);
53         for(int i=1;i<=n;i++)
54             for(int j=head[i];j;j=nxt[j])
55             {
56                 int y=to[j];
57                 if(bl[i]==bl[y]) continue;
58                 imin[bl[y]]=min(imin[bl[y]],w[j]);
59             }
60         long long ans=0;
61         for(int i=1;i<=scc;i++)
62             if(imin[i]<=10000000)
63                 ans+=imin[i];
64         printf("%lld\n",ans);
65     }
66     return 0;
67 }

 

版权声明:本文为heoitys原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/heoitys/p/11199054.html