zoukankan      html  css  js  c++  java
  • UVA 11865 Stream My Contest 组网 (朱刘算法,有向生成树,树形图)

    题意:

      给n个点编号为0~n-1,0号点为根,给m条边(含自环,重边),每条边有个代价,也有带宽。给定c,问代价不超过c,树形图的最小带宽的最大值能达到多少?

    思路:

      点数才60,而带宽范围也不大,可以进行二分穷举最小带宽,将小于穷举值的边“禁用”,进行求树形图!只要能求得树形图,说明带宽还能继续往上提。

      注:如果只有根,即n=1,那么输出其中最小的一条边的带宽。而求树形图比较简单,用朱刘算法O(n*m),网上有模板。

      朱刘算法的精髓在于:缩点就缩得彻底,将原来的图都给改掉了。如果产生了环,那就缩点,缩点后,属于原来环上的边u-v就会变成一条自环(没用的)。而找环的技术也经典,只是复杂度看起来不止O(n)了,随着环越来越少,复杂度越高。

      

      1 #include <bits/stdc++.h>
      2 #define INF 0x7f7f7f7f
      3 #define pii pair<int,int>
      4 #define LL long long
      5 using namespace std;
      6 const int M=10010;
      7 const int N=100;
      8 
      9 struct node
     10 {
     11     int from,to;
     12     int bps,cost;
     13     node(){};
     14     node(int from,int to,int bps,int cost):from(from),to(to),bps(bps),cost(cost){};
     15 }edge[M], cpy[M];
     16 int edge_cnt, n, m, c;
     17 
     18 void add_node(int from,int to,int bps,int cost)
     19 {
     20     edge[edge_cnt]=node(from, to, bps, cost);
     21     cpy[edge_cnt]=node(from, to, bps, cost);//拷贝
     22     edge_cnt++;
     23 }
     24 
     25 int far[N], In[N], ID[N], vis[N];
     26 
     27 bool MST(int bps,int cost,int n,int root)
     28 {
     29     LL ans=0;
     30     while(true)
     31     {
     32         //找最小边
     33         for(int i=0; i<n; i++)  In[i]=INF;
     34         for(int i=0; i<edge_cnt; i++)
     35         {
     36             int u=edge[i].from;
     37             int v=edge[i].to;
     38             if(edge[i].cost<In[v] && u!=v && edge[i].bps>=bps)
     39             {
     40                 far[v]=u;
     41                 In[v]=edge[i].cost;
     42             }
     43         }
     44 
     45         //判断是否与生成树
     46         for(int i=0; i<n; i++)
     47         {
     48             if(i==root)     continue;
     49             if(In[i]==INF)  return false;    //缩点后root可能不为0
     50         }
     51 
     52         //找环
     53         int cntnode=0;
     54         memset(ID,  -1, sizeof(ID));     //ID保存的是环的编号
     55         memset(vis, -1, sizeof(vis));
     56         In[root]=0;
     57         for(int i=0; i<n; i++)
     58         {
     59             ans+=In[i];
     60             int v=i;
     61             while( vis[v]!=i && ID[v]==-1 && v!=root )  //用vis记录本次寻根所走过的点
     62             {
     63                 vis[v]=i;
     64                 v=far[v];
     65             }
     66             if(ID[v]==-1 && v!=root)
     67             {
     68                 for(int u=far[v]; u!=v; u=far[u])
     69                 {
     70                     ID[u]=cntnode;
     71                 }
     72                 ID[v]=cntnode++;
     73             }
     74         }
     75 
     76         if(cntnode==0)  break;
     77 
     78         for(int i=0;i<n;i++)   //不成环的点,单独作为1个环
     79             if(ID[i]==-1)    ID[i]=cntnode++;
     80 
     81         //有环
     82         for(int i=0; i<edge_cnt; i++)
     83         {
     84             int v=edge[i].to;
     85             edge[i].from =ID[edge[i].from];  //真的缩点,只不过边数仍然一样多
     86             edge[i].to =ID[edge[i].to];
     87             if(edge[i].from!=edge[i].to)
     88             {
     89                 edge[i].cost-=In[v];    //如果u和v不是同个环,那么v的入边的大小得改了。
     90             }
     91         }
     92         n=cntnode;
     93         root=ID[root];
     94     }
     95     if(ans<=cost)    return  true;
     96     else    return false;
     97 }
     98 
     99 
    100 int cal(int L,int R,int root)
    101 {
    102     while(L<R)    //二分答案
    103     {
    104         for(int i=0; i<edge_cnt; i++)    edge[i]=cpy[i];    //注意要复制,因为原来的已经改变了
    105 
    106         int mid=L+(R-L+1)/2;
    107         if( MST(mid, c, n, root) )  L=mid;
    108         else       R=mid-1;
    109     }
    110     return L;
    111 }
    112 
    113 int main()
    114 {
    115     //freopen("input.txt", "r", stdin);
    116     int t, u, v, a, b;
    117     cin>>t;
    118     while(t--)
    119     {
    120         scanf("%d%d%d", &n, &m, &c);
    121         edge_cnt=0;
    122         int down=INF, up=0;     //找最大和最小进行二分
    123 
    124         for(int i=0; i<m; i++)
    125         {
    126             scanf("%d%d%d%d", &u, &v, &a, &b);
    127             down=min(down, a);
    128             up=max(up, a);
    129             add_node(u, v, a, b);
    130         }
    131 
    132         if(!MST(down, c, n, 0)) printf("streaming not possible.
    ");
    133         else      printf("%d kbps
    ",  cal(down, up, 0));   //只有根的情况,输出down
    134     }
    135     return 0;
    136 }
    AC代码
  • 相关阅读:
    less css
    Eclipse折叠代码 coffee bytes code folding
    jTDS jdbc驱动
    十点建议:从程序员变企业家 10 Tips for Moving From Programmer to Entrepreneur
    转:Hibernate Query examples (HQL) 示例
    [转]风雨7年话3D 长篇连载
    在游戏中使用CEGUI —— 第一章(底层)
    plusMark(正号硬件性能测试器)
    我会在月底之前将CEGUI相关的东西共享出来
    近期继超女之后的2大新闻
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4716571.html
Copyright © 2011-2022 走看看