您的位置:首页 > 其它

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

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: