hdu 2121 Ice_cream’s world II
2012-08-10 19:37
316 查看
卡了我好几天的最小树形图........
这题是要找出最小树形图,而且如果有多种情况,输出根编号最小的一棵。这是当时个人赛的题目,赛后才知道这是最小树形图,还知道这种图的算法是中国人研发的,叫做朱刘算法。算法很容易理解,不过我一直都没尝试做几个题目。前几天,回想起个人赛有一道最小树形图的题目,于是便打算拿这题来试刀。
朱刘算法是O(VE)的一个算法,最糟糕的时候要计算V*E次,最理想的状态就是直接E次的边查找,恰好构造出无环的最小树形图。
刚开始打的代码是研究一本模板后,根据思想和变量的设定来尝试打出来。第一次,是直接抄模板,试试看模板能不能用。对这道题,我刚开始是用暴力朱刘算法的方法,也就是更换V次根来找最小树形图。当然,O(V^2E)的复杂度是必然过不了的。那时想不到这题(不定根的最小树形图)可以有一个十分巧妙的方法来解决,就是添加一个虚拟根,然后把虚拟根指向到每一个顶点处。不过这样还没完,添加的每条边都要赋予相同的权值,表明每个顶点都有机会充当根。这时还要考虑的一个问题就是,边权到底要多少呢?答案是明显的,是越大越好,同时要保证计算不会溢出,那就可以了。于是,我们可以设置一个比所有真实的边权的和要大一点的值。
我的代码是参考这个博客写出来的:/article/5032057.html
我打这题一共重打了4次,前几次都是参照刚开始学的模板的储存方式来打的。不过,TLE了好多次,修改了也好多次,发现还是过不了,于是我就模仿上面的链接里的代码来写。两种思想是一样的,不过,博客的是储存边,直接用边处理的,而模板的是储存点和点的关系的。我看了一下,发现直接储存边好像更加优越。
于是,今天下午我去机房的时候顺便尝试储存边的方法切了这题。第一次写,环的处理方法跟博客的处理方法不一样,又TLE,十分郁闷!当时猜想,应该是某些数据使得程序死循环了吧。因为我之前写的几次都是有漏洞的,而且我很容易就构造出死循环的数据。我不想再纠结这个问题太久了,所以我再看多一遍博客的方法,确定能够记住了后,自己就像默写一样,几乎一样的将代码打了一遍。不过,这次还是没有很好的记住,需要我debug。debug着,太累了,然后睡了两个小时..... - - 起来后,我再添加一点debug的信息,终于被我发现问题。改过来以后,测试了几组数据,过了,交上去,也过了!
终于,今天我解决了这个卡了好几天的问题。这不是难,应该是我对算法理解不够透彻,所以一直不能debug出问题。
View Code
这题是要找出最小树形图,而且如果有多种情况,输出根编号最小的一棵。这是当时个人赛的题目,赛后才知道这是最小树形图,还知道这种图的算法是中国人研发的,叫做朱刘算法。算法很容易理解,不过我一直都没尝试做几个题目。前几天,回想起个人赛有一道最小树形图的题目,于是便打算拿这题来试刀。
朱刘算法是O(VE)的一个算法,最糟糕的时候要计算V*E次,最理想的状态就是直接E次的边查找,恰好构造出无环的最小树形图。
刚开始打的代码是研究一本模板后,根据思想和变量的设定来尝试打出来。第一次,是直接抄模板,试试看模板能不能用。对这道题,我刚开始是用暴力朱刘算法的方法,也就是更换V次根来找最小树形图。当然,O(V^2E)的复杂度是必然过不了的。那时想不到这题(不定根的最小树形图)可以有一个十分巧妙的方法来解决,就是添加一个虚拟根,然后把虚拟根指向到每一个顶点处。不过这样还没完,添加的每条边都要赋予相同的权值,表明每个顶点都有机会充当根。这时还要考虑的一个问题就是,边权到底要多少呢?答案是明显的,是越大越好,同时要保证计算不会溢出,那就可以了。于是,我们可以设置一个比所有真实的边权的和要大一点的值。
我的代码是参考这个博客写出来的:/article/5032057.html
我打这题一共重打了4次,前几次都是参照刚开始学的模板的储存方式来打的。不过,TLE了好多次,修改了也好多次,发现还是过不了,于是我就模仿上面的链接里的代码来写。两种思想是一样的,不过,博客的是储存边,直接用边处理的,而模板的是储存点和点的关系的。我看了一下,发现直接储存边好像更加优越。
于是,今天下午我去机房的时候顺便尝试储存边的方法切了这题。第一次写,环的处理方法跟博客的处理方法不一样,又TLE,十分郁闷!当时猜想,应该是某些数据使得程序死循环了吧。因为我之前写的几次都是有漏洞的,而且我很容易就构造出死循环的数据。我不想再纠结这个问题太久了,所以我再看多一遍博客的方法,确定能够记住了后,自己就像默写一样,几乎一样的将代码打了一遍。不过,这次还是没有很好的记住,需要我debug。debug着,太累了,然后睡了两个小时..... - - 起来后,我再添加一点debug的信息,终于被我发现问题。改过来以后,测试了几组数据,过了,交上去,也过了!
终于,今天我解决了这个卡了好几天的问题。这不是难,应该是我对算法理解不够透彻,所以一直不能debug出问题。
View Code
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define debug 0 typedef __int64 ll; ll max2(ll a, ll b) {return a > b ? a : b; } ll min2(ll a, ll b) {return a < b ? a : b; } const int maxn = 1001; const ll inf = 0x7f7f7f7f; int in[maxn][maxn], out[maxn][maxn]; // in-arc out-arc ll cost[maxn][maxn], min_cost; ll mf_arc[maxn]; // min-fold-arc int pre[maxn], fold[maxn]; bool del[maxn], vis[maxn], mk[maxn]; void init(int vn){ // initialize the variable for (int i = 0; i <= vn; i++){ in[i][0] = out[i][0] = 0; del[i] = false; pre[i] = fold[i] = i; mf_arc[i] = inf; for (int j = 0; j <= vn; j++){ cost[i][j] = inf; } } } void min_tree(int vn, int &rt, int root){ int i, j, k, cb, t, tmp; bool cycle; #if debug for (i = 0; i <= vn; i++){ for (j = 0; j <= vn; j++){ if (cost[i][j] == inf) printf("inf "); else printf("%3I64d ", cost[i][j]); } puts(""); } puts(""); #endif min_cost = 0; while (true){ // run until no cycles cycle = false; for (i = 0; i <= vn; i++){ if (del[i] || i == root) continue; cost[i][i] = inf; pre[i] = i; for (j = 1; j <= in[i][0]; j++){ if (del[in[i][j]]) continue; if (cost[pre[i]][i] > cost[in[i][j]][i]){ pre[i] = in[i][j]; } } } // find the min-in-arc #if debug for (i = 1; i <= vn; i++){ printf("%d : pre %d fold %d\n", i, pre[i], fold[i]); } puts(""); #endif for (i = 0; i <= vn; i++) vis[i] = false, mk[i] = false; for (i = 0; i <= vn; i++){ if (vis[i] || del[i] || i == root) continue; for (j = pre[i]; !vis[j]; vis[j] = true, j = pre[j]); cb = j;// suppose cb is cycle-begin if (j == root || mk[j]) { mk[i] = true; continue; // if can reach the root, not cycle } cycle = true; #if debug printf("when i %d cycle begin at %d\n", i, cb); printf("sub-vexs: "); for (j = pre[cb]; j != cb; j = pre[j]) printf("%d ", j); puts(""); #endif min_cost += cost[pre[cb]][cb]; for (j = pre[cb]; j != cb; j = pre[j]){ del[j] = true; min_cost += cost[pre[j]][j]; } for (j = 1; j <= in[cb][0]; j++){ if (del[in[cb][j]]) continue; cost[in[cb][j]][cb] -= cost[pre[cb]][cb]; if (!in[cb][j]){ if (mf_arc[cb] > cost[in[cb][j]][cb]) fold[cb] = fold[cb], mf_arc[cb] = cost[in[cb][j]][cb]; else if (mf_arc[cb] == cost[in[cb][j]][cb]) fold[cb] = min2(fold[cb], cb); #if debug printf("mf_arc %d : %I64d fold %d\n", cb, mf_arc[cb], fold[cb]); #endif } } cost[pre[cb]][cb] = 0; for (j = pre[cb]; j != cb; j = pre[j]){ for (k = 1; k <= out[j][0]; k++){ t = out[j][k]; if (del[t] || t == cb || t == root) continue; if (cost[cb][t] == inf){ out[cb][++out[cb][0]] = t; in[t][++in[t][0]] = cb; } cost[cb][t] = min2(cost[cb][t], cost[j][t]); } for (k = 1; k <= in[j][0]; k++){ t = in[j][k]; if (del[t] || t == cb) continue; if (cost[t][cb] == inf){ in[cb][++in[cb][0]] = t; out[t][++out[t][0]] = cb; } tmp = cost[t][j] - cost[pre[j]][j]; cost[t][cb] = min2(cost[t][cb], tmp); if (t == root){ if (mf_arc[cb] > tmp) fold[cb] = fold[j], mf_arc[cb] = tmp; else if (mf_arc[cb] == tmp) fold[cb] = min2(fold[j], fold[cb]); #if debug printf("sub_mf_arc %d : %I64d fold %d\n", cb, mf_arc[cb], fold[cb]); #endif } } cost[pre[j]][j] = 0; } #if debug printf("fold %d out %d\n", cb, fold[cb]); #endif break; } if (!cycle){ for (i = 0; i <= vn; i++){ if (i == root || del[i]) continue; min_cost += cost[pre[i]][i]; if (pre[i] == root) rt = fold[i]; } break; } #if debug printf("vex deleted: "); for (i = 0; i <= vn; i++){ if (del[i]) printf("%d ", i); } puts("\n"); printf("min_cost %I64d\n", min_cost); for (i = 0; i <= vn; i++){ for (j = 0; j <= vn; j++){ if (cost[i][j] == inf) printf("inf "); else printf("%3I64d ", cost[i][j]); } puts(""); } puts(""); #endif } #if debug printf("min_cost %I64d\n", min_cost); for (i = 0; i <= vn; i++){ printf("%d : pre %2d fold %2d\n", i, pre[i], fold[i]); } puts(""); #endif } int main(){ int n, m; int a, b, rt = 0; ll c, sum; while (~scanf("%d%d", &n, &m)){ init(n); sum = 0; for (int i = 0; i < m; i++){ scanf("%d%d%I64d", &a, &b, &c); a++; b++; sum += c; cost[a][b] = min2(cost[a][b], c); in[b][++in[b][0]] = a; out[a][++out[a][0]] = b; } sum++; #if debug printf("sum %I64d\n", sum); #endif for (int i = 1; i <= n; i++){ in[i][++in[i][0]] = 0; out[0][++out[0][0]] = i; cost[0][i] = sum; } #if debug puts("in-arcs:"); for (int i = 0; i <= n; i++){ printf("%d : ", i); for (int j = 1; j <= in[i][0]; j++){ printf("%d ", in[i][j]); } puts(""); } puts(""); #endif min_tree(n, rt, 0); if (min_cost < (sum << 1)){ printf("%I64d %d\n", min_cost - sum, rt - 1); } else{ puts("impossible"); } puts(""); } return 0; }
相关文章推荐
- HDU 2121 Ice_cream’s world II (不定根最小树形图)
- HDU 2121 Ice_cream’s world II
- HDU 2121 Ice_cream’s world II(不定根最小树形图)
- [HDU 2121] Ice_cream’s world II 最小树形图
- HDU 2121 Ice_cream’s world II(不定根最小树形图)
- HDU ACM 2121 Ice_cream’s world II (无根最小树形图)
- HDU - 2121 Ice_cream’s world II(朱刘算法+虚根)
- HDU 2121 Ice_cream’s world II
- HDU 2121 Ice_cream’s world II(不定根最小树形图)
- HDU 2121 Ice_cream’s world II 不定根最小树形图
- HDU-2121-Ice_cream’s world II 9(不定根最小树形图)
- HDU 2121 Ice_cream’s world II 无固定点的最小树形图 朱刘算法
- Ice_cream’s world II - HDU 2121 朱刘算法
- hdu 2121 Ice_cream’s world II(最小树形图,不定根)
- hdu 2121 Ice_cream’s world II(不定根的最小树形图)
- HDU 2121 Ice_cream’s world II
- hdu 2121 Ice_cream’s world II(无定根的最小树形图)
- hdu 2121 Ice_cream’s world II(无固定根最小树形图)
- Ice_cream’s world II - HDU 2121 - 最小树形图
- HDU - 2121-Ice_cream’s world II-无根最小树形图