HDU-2121 Ice_cream’s world II
阿新 • • 發佈:2018-11-02
最小樹形圖問題,但是沒有給定根,需要自己選根
可以加一個虛根,連向其他所有點,權值為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; }