zoukankan      html  css  js  c++  java
  • hdu 2121 Ice_cream’s world II

      卡了我好几天的最小树形图........

      这题是要找出最小树形图,而且如果有多种情况,输出根编号最小的一棵。这是当时个人赛的题目,赛后才知道这是最小树形图,还知道这种图的算法是中国人研发的,叫做朱刘算法。算法很容易理解,不过我一直都没尝试做几个题目。前几天,回想起个人赛有一道最小树形图的题目,于是便打算拿这题来试刀。

      朱刘算法是O(VE)的一个算法,最糟糕的时候要计算V*E次,最理想的状态就是直接E次的边查找,恰好构造出无环的最小树形图。

      刚开始打的代码是研究一本模板后,根据思想和变量的设定来尝试打出来。第一次,是直接抄模板,试试看模板能不能用。对这道题,我刚开始是用暴力朱刘算法的方法,也就是更换V次根来找最小树形图。当然,O(V^2E)的复杂度是必然过不了的。那时想不到这题(不定根的最小树形图)可以有一个十分巧妙的方法来解决,就是添加一个虚拟根,然后把虚拟根指向到每一个顶点处。不过这样还没完,添加的每条边都要赋予相同的权值,表明每个顶点都有机会充当根。这时还要考虑的一个问题就是,边权到底要多少呢?答案是明显的,是越大越好,同时要保证计算不会溢出,那就可以了。于是,我们可以设置一个比所有真实的边权的和要大一点的值。

      我的代码是参考这个博客写出来的:http://www.cnblogs.com/wuyiqi/archive/2011/09/07/2169708.html

       我打这题一共重打了4次,前几次都是参照刚开始学的模板的储存方式来打的。不过,TLE了好多次,修改了也好多次,发现还是过不了,于是我就模仿上面的链接里的代码来写。两种思想是一样的,不过,博客的是储存边,直接用边处理的,而模板的是储存点和点的关系的。我看了一下,发现直接储存边好像更加优越。

      于是,今天下午我去机房的时候顺便尝试储存边的方法切了这题。第一次写,环的处理方法跟博客的处理方法不一样,又TLE,十分郁闷!当时猜想,应该是某些数据使得程序死循环了吧。因为我之前写的几次都是有漏洞的,而且我很容易就构造出死循环的数据。我不想再纠结这个问题太久了,所以我再看多一遍博客的方法,确定能够记住了后,自己就像默写一样,几乎一样的将代码打了一遍。不过,这次还是没有很好的记住,需要我debug。debug着,太累了,然后睡了两个小时..... - -   起来后,我再添加一点debug的信息,终于被我发现问题。改过来以后,测试了几组数据,过了,交上去,也过了!

      终于,今天我解决了这个卡了好几天的问题。这不是难,应该是我对算法理解不够透彻,所以一直不能debug出问题。

    View Code
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cmath>
      4 #include <cstdlib>
      5 #include <iostream>
      6 
      7 typedef __int64  ll;
      8 const int maxv = 1100;
      9 const int maxe = 12000;
     10 const ll inf = 0x7f7f7f7f;
     11 
     12 int in[maxv], vis[maxv], pre[maxv], fold[maxv], pos;
     13 //   in-arc's cost              pre-vex      new vex-num
     14 ll min_cost;
     15 struct edge{
     16     int b, e;
     17     ll c;
     18 }E[maxe];
     19 // save arcs
     20 
     21 bool make_tree(int root, int v, int e){
     22     int cnt;
     23 
     24     min_cost = 0;
     25     while (true){
     26         for (int i = 0; i < v; i++){
     27             in[i] = inf;
     28             pre[i] = -1;
     29         } // suppose every vex does not have pre-vex
     30         for (int i = 0; i < e; i++){
     31             int s = E[i].b;
     32             int t = E[i].e;
     33 
     34             if (in[t] > E[i].c && s != t){
     35                 in[t] = E[i].c;
     36                 pre[t] = s;
     37                 if (s == root){
     38                     pos = i;
     39                 } // record the vex whose pre-vex is the vertual root by using the edge's number
     40             }
     41         } // find the min-in-arc of every vex
     42 #ifndef ONLINE_JUDGE
     43         for (int i = 0; i < v; i++){
     44             printf("pre %d : %d\n", i, pre[i]);
     45         }
     46         printf("root  %d\n", root);
     47 #endif
     48         for (int i = 0; i < v; i++){
     49             vis[i] = -1, fold[i] = -1;
     50             if (in[i] == inf && i != root) return false;
     51         } // ensure whether the tree can be build, of course, it is no use in this problem
     52 
     53         cnt = 0;
     54         in[root] = 0;
     55         for (int i = 0, j, k; i < v; i++){
     56             if (i == root) continue;
     57             min_cost += in[i];
     58             vis[i] = i;
     59             for (j = pre[i]; vis[j] != i && fold[j] == -1 && j != root; j = pre[j]){
     60                 vis[j] = i;
     61             }
     62             if (j == root || fold[j] != -1) continue;
     63 
     64             k = j;
     65             for (fold[k] = cnt, k = pre[k]; k != j; k = pre[k]) fold[k] = cnt;
     66             cnt++;
     67         } // find circle and re-number every vex
     68 #ifndef ONLINE_JUDGE
     69         printf("cnt %d\n", cnt);
     70 #endif
     71         if (!cnt) return true;
     72         for (int i = 0; i < v; i++){
     73             if (fold[i] == -1) fold[i] = cnt++;
     74         } // re-number the rest single vex
     75         for (int i = 0; i < e; i++){
     76             int s = E[i].b;
     77             int t = E[i].e;
     78 
     79             E[i].b = fold[s];
     80             E[i].e = fold[t];
     81             if (E[i].b != E[i].e)
     82                 E[i].c -= in[t];
     83         } // refresh every arcs
     84         root = fold[root];
     85         v = cnt;
     86     }
     87 }
     88 
     89 
     90 bool deal(){
     91     int n, m;
     92     ll e_sum = 0;
     93 
     94     if (scanf("%d%d", &n, &m) == EOF) return false;
     95     for (int i = 0; i < m; i++){
     96         scanf("%d%d%I64d", &E[i].b, &E[i].e, &E[i].c);
     97         E[i].b++; E[i].e++;
     98         e_sum += E[i].c;
     99     }
    100     e_sum++;
    101     for (int i = 0; i < n; i++){
    102         E[m + i].b = 0;
    103         E[m + i].e = i + 1;
    104         E[m + i].c = e_sum;
    105     } // build virtual root
    106     make_tree(0, n + 1, m + n);
    107     if (min_cost < (e_sum << 1)){
    108         printf("%I64d %d\n", min_cost - e_sum, pos - m);
    109     }
    110     else puts("impossible");
    111     puts("");
    112 
    113     return true;
    114 }
    115 
    116 int main(){
    117 #ifndef ONLINE_JUDGE
    118     freopen("in","r",stdin);
    119 #endif
    120     while (deal());
    121 
    122     return 0;
    123 }

       这是模板的方法,本地的一些比较刁难的数据都能通过,不过就是不知道怎样超时!留着,以后慢慢研究!

    View Code
      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <cmath>
      5 #include <algorithm>
      6 
      7 #define debug 0
      8 
      9 typedef __int64 ll;
     10 ll max2(ll a, ll b) {return a > b ? a : b; }
     11 ll min2(ll a, ll b) {return a < b ? a : b; }
     12 
     13 const int maxn = 1001;
     14 const ll inf = 0x7f7f7f7f;
     15 
     16 int in[maxn][maxn], out[maxn][maxn];
     17 //   in-arc          out-arc
     18 ll cost[maxn][maxn], min_cost;
     19 ll mf_arc[maxn];
     20 // min-fold-arc
     21 int pre[maxn], fold[maxn];
     22 bool del[maxn], vis[maxn], mk[maxn];
     23 
     24 void init(int vn){ // initialize the variable
     25     for (int i = 0; i <= vn; i++){
     26         in[i][0] = out[i][0] = 0;
     27         del[i] = false;
     28         pre[i] = fold[i] = i;
     29         mf_arc[i] = inf;
     30         for (int j = 0; j <= vn; j++){
     31             cost[i][j] = inf;
     32         }
     33     }
     34 }
     35 
     36 void min_tree(int vn, int &rt, int root){
     37     int i, j, k, cb, t, tmp;
     38     bool cycle;
     39 
     40     #if debug
     41     for (i = 0; i <= vn; i++){
     42         for (j = 0; j <= vn; j++){
     43             if (cost[i][j] == inf) printf("inf ");
     44             else printf("%3I64d ", cost[i][j]);
     45         }
     46         puts("");
     47     }
     48     puts("");
     49     #endif
     50     min_cost = 0;
     51     while (true){ // run until no cycles
     52         cycle = false;
     53         for (i = 0; i <= vn; i++){
     54             if (del[i] || i == root) continue;
     55             cost[i][i] = inf;
     56             pre[i] = i;
     57             for (j = 1; j <= in[i][0]; j++){
     58                 if (del[in[i][j]]) continue;
     59                 if (cost[pre[i]][i] > cost[in[i][j]][i]){
     60                     pre[i] = in[i][j];
     61                 }
     62             }
     63         } // find the min-in-arc
     64         #if debug
     65         for (i = 1; i <= vn; i++){
     66             printf("%d : pre  %d   fold  %d\n", i, pre[i], fold[i]);
     67         }
     68         puts("");
     69         #endif
     70         for (i = 0; i <= vn; i++) vis[i] = false, mk[i] = false;
     71         for (i = 0; i <= vn; i++){
     72             if (vis[i] || del[i] || i == root) continue;
     73             for (j = pre[i]; !vis[j]; vis[j] = true, j = pre[j]);
     74             cb = j;// suppose cb is cycle-begin
     75             if (j == root || mk[j]) {
     76                 mk[i] = true;
     77                 continue; // if can reach the root, not cycle
     78             }
     79             cycle = true;
     80             #if debug
     81             printf("when i %d   cycle begin at %d\n", i, cb);
     82             printf("sub-vexs: ");
     83             for (j = pre[cb]; j != cb; j = pre[j]) printf("%d ", j);
     84             puts("");
     85             #endif
     86             min_cost += cost[pre[cb]][cb];
     87             for (j = pre[cb]; j != cb; j = pre[j]){
     88                 del[j] = true;
     89                 min_cost += cost[pre[j]][j];
     90             }
     91             for (j = 1; j <= in[cb][0]; j++){
     92                 if (del[in[cb][j]]) continue;
     93                 cost[in[cb][j]][cb] -= cost[pre[cb]][cb];
     94                 if (!in[cb][j]){
     95                     if (mf_arc[cb] > cost[in[cb][j]][cb])
     96                         fold[cb] = fold[cb], mf_arc[cb] = cost[in[cb][j]][cb];
     97                     else if (mf_arc[cb] == cost[in[cb][j]][cb])
     98                         fold[cb] = min2(fold[cb], cb);
     99                     #if debug
    100                     printf("mf_arc %d : %I64d    fold %d\n", cb, mf_arc[cb], fold[cb]);
    101                     #endif
    102                 }
    103             }
    104             cost[pre[cb]][cb] = 0;
    105             for (j = pre[cb]; j != cb; j = pre[j]){
    106                 for (k = 1; k <= out[j][0]; k++){
    107                     t = out[j][k];
    108                     if (del[t] || t == cb || t == root) continue;
    109                     if (cost[cb][t] == inf){
    110                         out[cb][++out[cb][0]] = t;
    111                         in[t][++in[t][0]] = cb;
    112                     }
    113                     cost[cb][t] = min2(cost[cb][t], cost[j][t]);
    114                 }
    115                 for (k = 1; k <= in[j][0]; k++){
    116                     t = in[j][k];
    117                     if (del[t] || t == cb) continue;
    118                     if (cost[t][cb] == inf){
    119                         in[cb][++in[cb][0]] = t;
    120                         out[t][++out[t][0]] = cb;
    121                     }
    122                     tmp = cost[t][j] - cost[pre[j]][j];
    123                     cost[t][cb] = min2(cost[t][cb], tmp);
    124                     if (t == root){
    125                         if (mf_arc[cb] > tmp)
    126                             fold[cb] = fold[j], mf_arc[cb] = tmp;
    127                         else if (mf_arc[cb] == tmp)
    128                             fold[cb] = min2(fold[j], fold[cb]);
    129                         #if debug
    130                         printf("sub_mf_arc %d : %I64d    fold %d\n", cb, mf_arc[cb], fold[cb]);
    131                         #endif
    132                     }
    133                 }
    134                 cost[pre[j]][j] = 0;
    135             }
    136             #if debug
    137             printf("fold %d out %d\n", cb, fold[cb]);
    138             #endif
    139             break;
    140         }
    141         if (!cycle){
    142             for (i = 0; i <= vn; i++){
    143                 if (i == root || del[i]) continue;
    144                 min_cost += cost[pre[i]][i];
    145                 if (pre[i] == root) rt = fold[i];
    146             }
    147             break;
    148         }
    149         #if debug
    150         printf("vex deleted: ");
    151         for (i = 0; i <= vn; i++){
    152             if (del[i]) printf("%d ", i);
    153         }
    154         puts("\n");
    155         printf("min_cost  %I64d\n", min_cost);
    156         for (i = 0; i <= vn; i++){
    157             for (j = 0; j <= vn; j++){
    158                 if (cost[i][j] == inf) printf("inf ");
    159                 else printf("%3I64d ", cost[i][j]);
    160             }
    161             puts("");
    162         }
    163         puts("");
    164         #endif
    165     }
    166     #if debug
    167     printf("min_cost   %I64d\n", min_cost);
    168     for (i = 0; i <= vn; i++){
    169         printf("%d : pre  %2d       fold  %2d\n", i, pre[i], fold[i]);
    170     }
    171     puts("");
    172     #endif
    173 }
    174 
    175 
    176 int main(){
    177     int n, m;
    178     int a, b, rt = 0;
    179     ll c, sum;
    180 
    181     while (~scanf("%d%d", &n, &m)){
    182         init(n);
    183         sum = 0;
    184         for (int i = 0; i < m; i++){
    185             scanf("%d%d%I64d", &a, &b, &c);
    186             a++; b++;
    187             sum += c;
    188             cost[a][b] = min2(cost[a][b], c);
    189             in[b][++in[b][0]] = a;
    190             out[a][++out[a][0]] = b;
    191         }
    192         sum++;
    193         #if debug
    194         printf("sum  %I64d\n", sum);
    195         #endif
    196         for (int i = 1; i <= n; i++){
    197             in[i][++in[i][0]] = 0;
    198             out[0][++out[0][0]] = i;
    199             cost[0][i] = sum;
    200         }
    201         #if debug
    202         puts("in-arcs:");
    203         for (int i = 0; i <= n; i++){
    204             printf("%d : ", i);
    205             for (int j = 1; j <= in[i][0]; j++){
    206                 printf("%d ", in[i][j]);
    207             }
    208             puts("");
    209         }
    210         puts("");
    211         #endif
    212         min_tree(n, rt, 0);
    213         if (min_cost < (sum << 1)){
    214             printf("%I64d %d\n", min_cost - sum, rt - 1);
    215         }
    216         else{
    217             puts("impossible");
    218         }
    219         puts("");
    220     }
    221 
    222     return 0;
    223 }
  • 相关阅读:
    linux grep命令
    PHP 利用simplexml_load_file 读取XML对应的字段 然后存入mysql数据库
    php 设计模式之单类模式
    Mac C#开发工具Rider安利与环境配置教程
    模拟,贪心,枚举(二)
    模拟,贪心,枚举
    10.10 review
    review 10.9
    10.6 review
    9.28 review
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_2121_Lyon.html
Copyright © 2011-2022 走看看