• 杭电1827


    很久很久没有写过题解了,题解还是要多写,要多总结。
    题意:Wiskey知道他所有朋友的联系方式,知道他的朋友都有谁的联系方式,也知道联系他们要用的话费。现在他要通知所有朋友,最少要通知多少人,最少用多少电话费才够?
    Input
    多组测试数组,以EOF结束。
    第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
    接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
    接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。

    Output
    输出最小联系人数和最小花费。
    每个CASE输出答案一行。

    分析:一开始以为人数最少和话费最少要分两种不同的情况来算,后来发现话费最少的时候人数也是最少的。因为以人为节点,两人之间的联系方式为弧,建出来的有向图里,对于强连通分支,要且仅要通知里面任意一个人,那么这个强连通分支里面的所有人都能通知到,所以人数的最少代价是1,而通知话费最低的人能使话费代价最低。把强连通分支缩点,图就变成一堆单向连通分支了。每一个单向连通分支里面要且仅要通知入度为0的那个人,那么这个连通分支里面的所有人都能通知到,这是通知这些人代价最低的方法。

    View Code
     1 #include<cstdio>
     2 #include<vector>
     3 #include<stack>
     4 using std::stack;
     5 using std::vector;
     6 vector<int> arc[1001];
     7 stack<int> s;
     8 bool visited[1001],instack[1001],root[1001];
     9 int n,m,exp[1001],low[1001],num[1001],set[1001],root_exp[1001],rn,counter,minCall,minExp;
    10 int min(const int a,const int b)
    11 {
    12     return a>b?b:a;
    13 }
    14 void tarjan(int u)
    15 {
    16     int v,i;
    17     num[u]=low[u]=++counter;
    18     visited[u]=true;
    19     instack[u]=true;
    20     s.push(u);
    21     for(i=0;i<arc[u].size();i++)
    22     {
    23         v=arc[u][i];
    24         if(!visited[v])
    25         {
    26             tarjan(v);
    27             low[u]=min(low[u],low[v]);
    28         }
    29         else if(instack[v])
    30             low[u]=min(low[u],num[v]);
    31         if(root[v])
    32             root_exp[set[v]]=0;
    33     }
    34     if(num[u]==low[u])
    35     {
    36         root_exp[rn]=0xffffff;
    37         do
    38         {
    39             v=s.top();
    40             set[v]=rn;
    41             root[v]=true;
    42             if(root_exp[rn]>exp[v])
    43                 root_exp[rn]=exp[v];
    44             instack[v]=false;
    45             s.pop();
    46         }while(u!=v);
    47         rn++;
    48     }
    49 }
    50 int main()
    51 {
    52     int i,u,v;
    53     while(~scanf("%d%d",&n,&m))
    54     {
    55         for(i=1;i<=n;i++)
    56         {
    57             visited[i]=false;
    58             instack[i]=false;
    59             root[i]=false;
    60             scanf("%d",&exp[i]);
    61         }
    62         for(i=0;i<m;i++)
    63         {
    64             scanf("%d%d",&u,&v);
    65             arc[u].push_back(v);
    66         }
    67         counter=0;
    68         minCall=minExp=0;
    69         rn=0;
    70         for(i=1;i<=n;i++)
    71         {
    72             if(!visited[i])
    73                 tarjan(i);
    74         }
    75         for(i=0;i<rn;i++)
    76         {
    77             if(root_exp[i] && root_exp[i]!=0xffffff)
    78             {
    79                 minCall++;
    80                 minExp+=root_exp[i];
    81             }
    82         }
    83         for(i=1;i<=n;i++)
    84             arc[i].clear();
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    Jquery 学习一
    响应式设计
    微信开发一
    Ajax 技术二
    Ajax 技术一
    SVN版本控制软件
    正则表达式概述
    编写小游戏:贪吃蛇
    POJ 3356 AGTC(DP-最小编辑距离)
    算法模板の字符串处理
  • 原文地址:https://www.cnblogs.com/ZShogg/p/2942673.html
Copyright © 2020-2023  润新知