1. 程式人生 > >HDU2121:Ice_cream’s world II (虛根+有向圖最小生成樹)

HDU2121:Ice_cream’s world II (虛根+有向圖最小生成樹)

記錄 amp i++ imp others else mea 有趣 was

Ice_cream’s world II

Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 6849 Accepted Submission(s): 1818

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2121

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

題意:

給出一個有向圖,然後讓你選一個點作為起點,滿足從這個點可以到達其它點,並且總權和最小。

題解:

這就是一個不固定根的有向圖最小生成樹問題。思路還是挺有趣的。

我們不可能對每個點都跑一遍朱劉算法,所以考慮加一個虛根,然後邊權為INF,直接從這個虛根來跑就行了。最後答案就是跑出來的值減去INF。

但是這裏要註意的是一些不合法的情況,就是最後的答案大於2*INF時,因為這時,說明至少有兩個點入度為0,那麽說明不可能存在一顆有向圖的生成樹。

至於這個INF怎麽取,只要滿足大於等於邊權和就行了(我是這麽想的),不知道為什麽不能等於,這個問題我糾結了很久,就在剛才知道為什麽了。。

可能存在只有一條邊的情況,這時如果連邊權和,這時算法可能會出錯。

最後輸出起點,這裏比較巧妙,是根據邊來的,因為我們會改變點(算法縮點),但邊並沒有改變,具體見代碼:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#define INF 1e17
using namespace std;
typedef long long ll;
int n,m,t;
const int N = 1010,M = 10005;
struct Edge{
    int u,v,w;
}e[M<<1];
int pre[N]; //記錄前驅
int Rt;
ll id[N],vis[N],in[N];
ll dirMst(int root){
    ll ans=0;
    while(1){
        for(int i=0;i<=n;i++) in[i]=INF;
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        for(int i=1;i<=m;i++){
            int u=e[i].u,v=e[i].v,w=e[i].w;
            if(w<in[v] && v!=u){
                pre[v]=u;
                in[v]=w;
                if(u==root) Rt=i;
            }
        }           //求最小入邊集
        in[root]=0;
        pre[root]=root;
        for(int i=0;i<n;i++){
            if(in[i]==INF) return -1;
            ans+=in[i];
        }
        int idx = 0; //新標號
        for(int i=0;i<n;i++){
            if(vis[i] == -1 ){
                int u = i;
                while(vis[u] == -1){
                    vis[u] = i;
                    u = pre[u];
                }
                if(vis[u]!=i || u==root) continue;     //判斷是否形成環
                for(int v=pre[u];v!=u;v=pre[v] )
                    id[v]=idx;
                id[u] = idx++;
            }
        }
        if(idx==0) break;
        for(int i=0;i<n;i++){
            if(id[i]==-1) id[i]=idx++;
        }
        for(int i=1;i<=m;i++){
            e[i].w-=in[e[i].v];
            e[i].u=id[e[i].u];
            e[i].v=id[e[i].v];
        }
        n = idx;
        root = id[root];//給根新的標號
    }
    return ans;
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        ll sum = 0;
        for(int i=1;i<=m;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            e[i]=Edge{u,v,w};
            sum+=w;
        }
        sum++;
        for(int i=0;i<n;i++){
            e[i+m+1]=Edge{n,i,sum};
        }
        ll tmp=m;
        m+=n;n++;
        ll ans = dirMst(n-1);
        if(ans>2*sum) printf("impossible\n\n");
        else printf("%lld %lld\n\n",ans-sum,Rt-tmp-1ll);
    }
}

HDU2121:Ice_cream’s world II (虛根+有向圖最小生成樹)