zoukankan      html  css  js  c++  java
  • hdu2121 Ice_cream’s world II 最小树形图(难)

      这题比HDU4009要难一些。做了4009,大概知道了最小树形图的解法。拿到这题,最直接的想法是暴力。n个点试过去,每个都拿来做一次根。最后WA了,估计是超时了。(很多题都是TLE说成WA,用了G++才知道是TLE,不断修改代码也看不出来错哪了)。

      网上的正解是添加一个虚拟根(树根),使得它与n个点都有边相连。HDU4009题这样得到的边有实际的意义,好理解。这题这样得到的边不好理解,并且边权应该是多少也有讲究。别人的解题报告中是把这些边的权值设为原本所有边的权值之和加1。这样做的目的,是为了完全把这些边与原本的边区分开。最后得到的最小树形图有且仅有一条这样的边,并且这条边的终点就是所求的设立首都的点。从这里就可以看出边权设置的作用了。

      从4009和2121这两题来看,解无根的最小树形图问题的套路是:添加一个虚根,虚根与其他n个点要连边。其中比较重要的巧妙地使这些的权值有意义。这样就是“无根”转换为“有根”。然后就可以用模版了。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 const int N = 1010, M=10005,INF=0x3f3f3f3f;
      7 int pre[N],id[N],in[N],vis[N];
      8 int tot, Minr;//边数
      9 struct node
     10 {
     11     int u,v,w;
     12 }e[M];
     13 void adde(int i,int j,int k)
     14 {
     15     e[tot].u=i;e[tot].v=j;e[tot++].w=k;
     16 }
     17 long long  zhuliu(int root ,int vn)
     18 {
     19     long long  ans=0;
     20     int cnt;
     21     while(1)
     22     {
     23         for(int i=0;i<vn;i++)
     24             in[i]=INF,id[i]=-1,vis[i]=-1;
     25         for(int i=0;i<tot;i++)
     26         {
     27             if(in[e[i].v]>e[i].w && e[i].u!=e[i].v)
     28             {
     29                 pre[e[i].v]=e[i].u;
     30                 if(e[i].u==root) Minr=i;
     31                 in[e[i].v]=e[i].w;
     32             }
     33         }
     34         in[root]=0;
     35         pre[root]=root;
     36         for(int i=0;i<vn;i++)
     37         {
     38             ans+=in[i];
     39             if(in[i]==INF)
     40                 return -1;
     41         }
     42         cnt=0;
     43         for(int i=0;i<vn;i++)
     44         {
     45             if(vis[i]==-1)
     46             {
     47                 int t=i;
     48                 while(vis[t]==-1)
     49                 {
     50                     vis[t]=i;
     51                     t=pre[t];
     52                 }
     53                 if(vis[t]!=i || t==root) continue;
     54                 for(int j=pre[t];j!=t;j=pre[j])
     55                     id[j]=cnt;
     56                 id[t]=cnt++;
     57             }
     58         }
     59         if(cnt==0) break;
     60         for(int i=0;i<vn;i++)
     61             if(id[i]==-1)
     62                 id[i]=cnt++;
     63         for(int i=0;i<tot;i++)
     64         {
     65             int u,v;
     66             u=e[i].u;
     67             v=e[i].v;
     68             e[i].u=id[u];
     69             e[i].v=id[v];
     70             e[i].w-=in[v];
     71         }
     72         vn=cnt;
     73         root=id[root];
     74     }
     75     return ans;
     76 }
     77 
     78 int main()
     79 {
     80     //freopen("test.txt","r",stdin);
     81     int n,m,i,j,a,b,c,sum;
     82     while(scanf("%d%d",&n,&m)!=EOF)
     83     {
     84         tot=0;
     85         sum=0;
     86         for(i=0;i<m;i++)
     87         {
     88             scanf("%d%d%d",&a,&b,&c);
     89             adde(a,b,c);
     90             sum+=c;
     91         }
     92         sum++;
     93         for(i=0;i<n;i++)
     94         {
     95             adde(n,i,sum);
     96         }
     97         a=zhuliu(n,n+1);
     98         Minr-=m;
     99         if(a==-1||a>=2*sum) printf("impossible
    ");
    100         else printf("%d %d
    ",a-sum,Minr);
    101         printf("
    ");
    102     }
    103     return 0;
    104 }
    View Code
  • 相关阅读:
    【转】关于char * 与 char[]
    网页打印js代码
    无法用排他锁锁定该数据库,以执行该操作。 (Microsoft SQL Server,错误: 5030)
    CKEditor使用笔记
    FormView作为单独编辑页笔记
    用WindowsMediaPlayer控件写个WinForm播放器
    ListView搭配DataPager控件实现分页笔记
    如何禁用ViewState
    C#获取本机IP搜集整理7种方法
    ListView高效率分页笔记
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/3942698.html
Copyright © 2011-2022 走看看