poj 3164 Command Network

Command Network

 POJ - 3164 

题目大意:给出一个有向图,给出n个顶点的坐标,以及每条边连接的顶点,指定一个起点,找到一个方案,使得从这个点到其他所有点的路径的权值和最小,求最小权值

/*
    最小树形图模板题
    对缩点及其下面几个部分的解释: 
    vis相当于一个bool数组,标记某个点是否被访问过,因为每一次的for都要用vis,每一次赋值i可以避免memset false,快
    pre记录环上前驱,缩点之后点的编号会有所改变,用col记录
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 110
#define INF 2e9
using namespace std;
int n,m,pre[maxn],vis[maxn],col[maxn],num;
struct node{
    int from,to;
    double v;
}e[10010];
double x[maxn],y[maxn],in[maxn];
double zhuliu(){
    int tot=n,root=1,cirnum,to;
    double ans=0;
    while(1){
        for(int i=1;i<=tot;i++)in[i]=INF;
        for(int i=1;i<=m;i++)//枚举每条边 
            if(e[i].v<in[e[i].to]&&e[i].from!=e[i].to){
                pre[e[i].to]=e[i].from;
                in[e[i].to]=e[i].v;//in[i]表示指向i最小的边权 
            }
        for(int i=1;i<=tot;i++)//判断能否组成树形图 
            if(i!=root&&in[i]==INF)return -1;
        cirnum=0;
        memset(vis,0,sizeof(vis));
        memset(col,0,sizeof(col));
        in[root]=0;
        for(int i=1;i<=tot;i++){//缩点 
            ans+=in[i];
            to=i;
            while(vis[to]!=i&&!col[to]&&to!=root)
            {vis[to]=i;to=pre[to];}
            if(to!=root&&!col[to]){
                cirnum++;
                for(int j=pre[to];j!=to;j=pre[j])
                    col[j]=cirnum;
                col[to]=cirnum;
            }
        }
        if(!cirnum)break;
        for(int i=1;i<=tot;i++)
            if(!col[i])col[i]=++cirnum;
        for(int i=1;i<=m;i++){
            to=e[i].to;
            e[i].from=col[e[i].from];
            e[i].to=col[e[i].to];
            if(e[i].from!=e[i].to)e[i].v-=in[to];
        }
        tot=cirnum;
        root=col[root];
    }
    return ans;
}
int main(){
    double ans;
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
        num=0;
        int a,b;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a,&b);
            double dis=sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
            if(a!=b){
                e[++num].to=b;
                e[num].from=a;
                e[num].v=dis;
            }
        }
        m=num;
        ans=zhuliu();
        if(ans==-1)puts("poor snoopy");
        else printf("%.2lf
",ans);
    }
}
原文地址:https://www.cnblogs.com/thmyl/p/8119580.html