题目: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\n");
else printf("%d %d\n",ans-sum,pos-m);
printf("\n");
}
return 0;
}