最小树形图

最小树形图

   有根的情况: 直接求.

   无根的情况: 建立超级根节点,向每个点连有向边,边权大于所有边权和即可.

<span style="font-family:FangSong_GB2312;font-size:14px;"><strong>const int N=1010;
const int inf=1000000000;
struct node{
  int oldu,oldv;  //原始点
  int u,v,w;     //缩图后的点
}e[N*N];
int n,m,rt;
int pre[N],ID[N],vis[N];
int in[N];        //最小入边权值
int Directed_MST(int root,int n,int m){
  int oldroot=root;
  long long ret=0;
  while (1){
for (int i=1;i<=n;i++) in[i]=inf;
//找到最小入边
    for (int i=1;i<=m;i++){
        int u=e[i].u;
        int v=e[i].v;
        if (u!=v&&e[i].w<in[v]){
            pre[v]=u;in[v]=e[i].w;
            if (e[i].oldu==oldroot) rt=e[i].oldv;
        }
    }
    for (int i=1;i<=n;i++){
        if (i==root) continue;
        if (in[i]==inf) return -1;
}
//找环
    int nn=0;//新图的节点个数
    memset(ID,-1,sizeof(ID));
    memset(vis,-1,sizeof(vis));
    in[root]=0;
    for (int i=1;i<=n;i++){  //标记每一个环
        ret+=in[i];
        int v=i;
        while (v!=root&&ID[v]==-1&&vis[v]!=i){
            vis[v]=i;v=pre[v];
        }
        if (v!=root&&ID[v]==-1){  //将环缩成点
            ID[v]=++nn;
            for (int u=pre[v];u!=v;u=pre[u]) ID[u]=nn;
        }
    }
    if (nn==0) break; //无环
    for (int i=1;i<=n;i++)  //每一个不在环上的点添加到图中
        if (ID[i]==-1) ID[i]=++nn;
    //缩点重新标记
    for (int i=1;i<=m;i++){
        int u=e[i].u;
        int v=e[i].v;
        e[i].u=ID[u];
        e[i].v=ID[v];
        if (u!=v) e[i].w-=in[v];
    }
    n=nn;
    root=ID[root];
  }
  return  ret;
}
//输入
for (int i=1;i<=m;i++){
  scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
  e[i].oldu=e[i].u;e[i].oldv=e[i].v;
  sum+=e[i].w;
}
//建立超级根节点n+1
for (int i=1;i<=n;i++){
  e[++m].u=n+1;e[m].v=i;e[m].w=sum+1;
  e[m].oldu=e[m].u;e[m].oldv=e[m].v;
}
n++;
</strong></span>

如果ret!=-1&&ret<2*sum+2 表示有最小树形图结果为ret-sum-1,反正没有。

题目:

//poj 3164(模板题)

//uva 11183(模板题)

//hdu 2121(需要建立一个超级根节点)

//hdu 3072(最小树形图+强连通)

//hdu 4009(需要建立一个超级根节点)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值