HDU 2121 Ice_cream’s world II

HDU 2121 Ice_cream’s world II

Problem Description

After awarded lands to ACMers, the queen want to choose a city be her capital. This is an important event in ice_cream world, and it also a very difficult problem, because the world have N cities and M roads, every road was directed. Wiskey is a chief engineer in ice_cream world. The queen asked Wiskey must find a suitable location to establish the capital, beautify the roads which let capital can visit each city and the project’s cost as less as better. If Wiskey can’t fulfill the queen’s require, he will be punishing.

Input

Every case have two integers N and M (N<=1000, M<=10000), the cities numbered 0…N-1, following M lines, each line contain three integers S, T and C, meaning from S to T have a road will cost C.

Output

If no location satisfy the queen’s require, you must be output “impossible”, otherwise, print the minimum cost in this project and suitable city’s number. May be exist many suitable cities, choose the minimum number city. After every case print one blank.
 

Sample Input

3 1 0 1 1 4 4 0 1 10 0 2 10 1 3 20 2 3 30
 

Sample Output

impossible 40 0
 

Author

Wiskey
 

Source

HDU 2007-10 Programming Contest_WarmUp

Solution

朱劉算法

這個題目顯然是有向圖求最小生成樹,但是因爲沒有根節點,所以認爲的將所有節點編號+1,從而引入0號根節點

在用朱劉算法求最小生成樹的之前,先考慮一下引入的根節點的問題:根節點到每個節點的距離應該爲所有邊的距離之和再加上1,最後的最小費用應該是用求出來的值減去根節點到每個節點的距離

先考慮找到最小邊,其實就是用兩點間的距離不斷更新到其前驅節點(父節點)的最小距離,同時記錄前驅節點,更新到各點距離最小的點(輸出時需減去邊數)對於存在到期前驅節點的距離爲無窮大的點顯然不能由根節點遍歷到,那麼就不存在最小生成樹

然後找環,如果該節點通過其父節點能夠再次回到自己,那麼該節點就在一個環中,將該環全部標記爲一個序號,然後不停的遞歸搜索,直到沒有環爲止,就求出了最小生成樹(break掉)

最後縮點,把環裏的所有邊的起點和終點都改爲其環的編號,並修改環中點到其父節點的距離爲減去當前換種距離後的值,對於不在環中的點,按順序爲之標號即可

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L 1010
#define LL long long
#define inf 0x7f7f7f7f
using namespace std;

struct edge {
  int from, to, w;
} e[L * L];
int n, m, s, t, c, cnt, sum, in[L], pre[L], mr, vis[L], id[L];

inline void add(int a, int b, int v) {
  e[cnt].from = a, e[cnt].to = b, e[cnt++].w = v;
}

inline int MST(int root, int N, int E) {
  int res = 0;
  while (true) {
    for (int i = 0; i < N; ++i) in[i] = inf;
    memset(pre, -1, sizeof(pre));
    for (int i = 0; i < E; ++i) {
      int u = e[i].from, v = e[i].to, w = e[i].w;
      if (in[v] > w && u != v) {
	in[v] = w, pre[v] = u;//*
	if (u == root) mr = i;
      }
    }
    for (int i = 0; i < N; ++i) {
      if (i == root) continue;
      if (in[i] == inf) return -1;
    }
    int node = 0;
    memset(vis, -1, sizeof(vis));
    memset(id, -1, sizeof (id));
    in[root] = 0;//*
    for (int i = 0; i < N; ++i) {
      res += in[i];
      int v = i;
      while (id[v] == -1 && v != root && vis[v] != i) vis[v] = i, v = pre[v];
      if (id[v] == -1 && v != root){
	for (int u = pre[v]; u != v; u = pre[u]) id[u] = node;
	id[v] = node++;
      }
    }
    if (node == 0) break;
    for (int i = 0; i < N; ++i) if (id[i] == -1) id[i] = node++;
    for (int i = 0; i < E; ++i) {
      int u = e[i].from, v = e[i].to;
      e[i].from = id[u], e[i].to = id[v];
      if (e[i].from != e[i].to) e[i].w -= in[v];
    }
    N = node, root = id[root];//*
  }
  return res;
}

int main() {
  freopen("HDU2121.in", "r", stdin);
  freopen("HDU2121.out", "w", stdout);
  while (scanf("%d %d", &n, &m) != EOF) {
    cnt = 0, sum = 0;//*
    for (int i = 1; i <= m; ++i) {
      scanf("%d %d %d", &s, &t, &c);
      add(s + 1, t + 1, c);
      sum += c;
    }
    sum++;
    for (int i = 1; i <= n; ++i) add(0, i, sum);//*
    int ans = MST(0, n + 1, cnt);
    if (ans == -1 || ans >= sum * 2) printf("impossible\n\n");//*
    else printf("%d %d\n\n", ans - sum, mr - m);//*
  }
  return 0;
}

Summary

具體寫題目時的問題,已在代碼中標記出,簡單統計一下:

1、每組數據輸出後,還要輸出一個空行

2、不要忘記根節點到每一個節點的距離

3、每一次遞歸調用時,更新根節點應更新爲其對應的環的標號,而不是mr

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章