题目:http://acm.hdu.edu.cn/showproblem.php?pid=2121
题意:求一个有向图的不定根的最小树形图
构造一个虚根,将所有点都连向虚根,权值为所有边总和+1
然后用朱刘算法跑一遍
因为枚举的顺序是从小到大,所以得出的根一定是最小的字典序
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<queue> #include<stack> #include<map> #include<set> using namespace std; const int N=2e4+5; struct p { int u,v,w; }; p a[N]; int in[N],pre[N],id[N],use[N]; int pos; int solve(int root,int V,int E) { int ans=0; while(1) { memset(in,0x3f,sizeof(in)); for(int i=0;i<E;i++) { int u=a[i].u,v=a[i].v; if (a[i].w<in[v]&&u!=v) { pre[v]=u; in[v]=a[i].w; if (u==root) pos=i; } } for(int i=0;i<V;i++) { if (i==root) continue; if (in[i]==0x3f3f3f3f) return -1; } int tot=0; memset(id,-1,sizeof(id)); memset(use,-1,sizeof(use)); in[root]=0; for(int i=0;i<V;i++) { ans+=in[i]; int v=i; while(use[v]!=i&&id[v]==-1&&v!=root) { use[v]=i; v=pre[v]; } if (v!=root&&id[v]==-1) { for(int u=pre[v];u!=v;u=pre[u]) id[u]=tot; id[v]=tot++; } } if (tot==0) break; for(int i=0;i<V;i++) if (id[i]==-1) id[i]=tot++; for(int i=0;i<E;i++) { int u=a[i].u,v=a[i].v; a[i].u=id[u]; a[i].v=id[v]; if (id[u]!=id[v]) a[i].w-=in[v]; } V=tot; root=id[root]; } return ans; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { int sum=1; for(int i=0;i<m;i++) { scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); a[i].u++;a[i].v++; sum+=a[i].w; } for(int i=m;i<m+n;i++) { a[i].u=0;a[i].v=i-m+1; a[i].w=sum; } int ans=solve(0,n+1,n+m); if (ans==-1||ans-sum>=sum) printf("impossible "); else printf("%d %d ",ans-sum,pos-m); printf(" "); } return 0; }