1. 程式人生 > >HDU-2121 Ice_cream’s world II

HDU-2121 Ice_cream’s world II

最小樹形圖問題,但是沒有給定根,需要自己選根

可以加一個虛根,連向其他所有點,權值為sum=其他所有邊權值之和+1

從虛根形成最小樹形圖,得到的答案ans需減去sum

如果ans==-1||ans>=sum說明不能形成樹形圖

中途需要記錄最後連向虛根的邊,這個邊原本連向的另一個點就是選好的根

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1000+10;
const int M=1e4+1e3+10;
const ll INF=1e18;
struct Edge
{
    int u,v;
    ll w;
}edge[M];
int pre[N],vis[N],id[N];
ll in[N];
int p;
ll zhuliu(int root,int n,int m)
{
    ll sum=0;
    int u,v;
    while(true)
    {
        for(int i=0;i<n;i++)
            in[i]=INF;
        for(int i=0;i<m;i++)
        {
            Edge e=edge[i];
            if(e.u!=e.v&&e.w<in[e.v])
            {
                pre[e.v]=e.u;
                in[e.v]=e.w;
                if(e.u==root) p=i;
            }
        }
        for(int i=0;i<n;i++)
            if(i!=root&&in[i]==INF)
                return -1;
        int tn=0;
        memset(id,-1,sizeof(id));
        memset(vis,-1,sizeof(vis));
        in[root]=0;
        for(int i=0;i<n;i++)
        {
            sum+=in[i];
            v=i;
            while(vis[v]!=i&&id[v]==-1&&v!=root)
            {
                vis[v]=i;
                v=pre[v];
            }
            while(v!=root&&id[v]==-1)
            {
                for(int u=pre[v];u!=v;u=pre[u])
                    id[u]=tn;
                id[v]=tn++;
            }
        }
        if(tn==0) break;
        for(int i=0;i<n;i++)
            if(id[i]==-1)
                id[i]=tn++;
        for(int i=0;i<m;i++)
        {
            v=edge[i].v;
            edge[i].u=id[edge[i].u];
            edge[i].v=id[edge[i].v];
            if(edge[i].u!=edge[i].v)
                edge[i].w-=in[v];
        }
        n=tn;
        root=id[root];
    }
    return sum;
}
void solve(int n,int m,ll sum)
{
    ll ans=zhuliu(n-1,n,m);
    if(ans==-1||ans-sum>=sum) printf("impossible\n");
    else
    {
        ans-=sum;
        printf("%lld %d\n",ans,p-m+n-1);
    }
    printf("\n");
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int a,b,c;
        ll sum=0;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            edge[i].u=a;
            edge[i].v=b;
            edge[i].w=c;
            sum+=c;
        }
        sum++;
        for(int i=0;i<n;i++)
        {
            edge[m].u=n;
            edge[m].v=i;
            edge[m++].w=sum;
        }
        solve(n+1,m,sum);
    }
    return 0;
}