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 }
原文地址:https://www.cnblogs.com/LyonLys/p/hdu_2121_Lyon.html