[POJ3164]Command Network

题目

传送门

题解

最小树形图的模板题,主要是存一发朱刘算法的模板.

代码

#include<cstdio>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;

namespace IO{
    #define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
    #define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
    #define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
    #define writc(a,b) fwrit(a),putchar(b)
    #define mp(a,b) make_pair(a,b)
    #define fi first
    #define se second
    typedef long long LL;
    // typedef pair<int,int> pii;
    typedef unsigned long long ull;
    typedef unsigned uint;
    #define Endl putchar('\n')
    // #define int long long
    // #define int unsigned
    // #define int unsigned long long

    #define cg (c=getchar())
    template<class T>inline void read(T& x){
        char c;bool f=0;
        while(cg<'0'||'9'<c)f|=(c=='-');
        for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
        if(f)x=-x;
    }
    template<class T>inline T read(const T sample){
        T x=0;char c;bool f=0;
        while(cg<'0'||'9'<c)f|=(c=='-');
        for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
        return f?-x:x;
    }
    template<class T>void fwrit(const T x){//just short,int and long long
        if(x<0)return (void)(putchar('-'),fwrit(-x));
        if(x>9)fwrit(x/10);
        putchar(x%10^48);
    }
    template<class T>inline T Max(const T x,const T y){return x<y?y:x;}
    template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
    template<class T>inline T fab(const T x){return x>0?x:-x;}
    inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
    inline void getInv(int inv[],const int lim,const int MOD){
        inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    }
    inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
        return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
    }
}
using namespace IO;

const int maxn=100;
const int inf=(1<<30)-1;;

class Directed_MST{
private:
    /** @brief 图的信息*/
    double w[maxn+5][maxn+5];
    /** @brief 是否处在当前的环中*/
    bool incir[maxn+5];
    /** @brief 是否被收缩*/
    bool shrink[maxn+5];
    /** @brief 最小前驱边的指向*/
    int pre[maxn+5];
    /** @brief 节点个数*/
    int n;
    /** @brief 统计从 @p s 开始能到达多少个节点*/
    inline int bfs(const int s){
        int ret=1;
        bool vis[maxn+5]={};
        queue<int>q;
        q.push(s);vis[s]=true;
        while(!q.empty()){
            int u=q.front();q.pop();
            rep(v,1,n)if(w[u][v]<inf && !vis[v]){
                ++ret,vis[v]=true;
                q.push(v);
            }
        }return ret;
    }
public:
    inline void Init(const int N){
        n=N;
        memset(incir,0,sizeof incir);
        memset(shrink,0,sizeof shrink);
        rep(i,0,n)rep(j,i,n)
            w[i][j]=w[j][i]=inf;
    }
    inline void insert(const int u,const int v,double val){
        if(w[u][v]>val)w[u][v]=val;
    }
    inline double launch(const int s){
        double ans=0;
        if(bfs(s)!=n)return -1;
        while(1){//重复执行下列操作
            rep(i,1,n)if(i!=s && !shrink[i]){
                w[i][i]=inf,pre[i]=i;
                rep(j,1,n)if(!shrink[j] && w[j][i]<w[pre[i]][i])
                    pre[i]=j;
            }
            /** 找环, 以及环上的任意一个点*/
            int u;
            for(u=1;u<=n;++u)if(u!=s && !shrink[u]){
                int j=u,cnt=0;
                while(j!=s && pre[j]!=u &&cnt<=n)j=pre[j],++cnt;
                if(j==s || cnt>n)continue;
                break;
            }
            /** 没有环, 可以返回答案了*/
            if(u>n){
                rep(i,1,n)if(i!=s && !shrink[i])ans+=w[pre[i]][i];
                return ans;
            }
            /** 把环上的所有点全部缩到 u 上*/
            int p=u;
            memset(incir,0,sizeof incir);
            do{
                ans+=w[pre[p]][p],p=pre[p];
                incir[p]=shrink[p]=1;
            }while(p^u);
            shrink[u]=0;//这个点肯定没被缩进去
            rep(i,1,n)if(incir[i]){//枚举环上的点
                rep(j,1,n)if(!incir[j]){//非环上的点
                    if(w[u][j]>w[i][j])w[u][j]=w[i][j];//连出去的都是最优边
                    if(w[j][i]<inf && w[j][i]-w[pre[i]][i]<w[j][u])//更新入边
                        w[j][u]=w[j][i]-w[pre[i]][i];
                }
            }
        }return ans;
    }
}G;

int n,m;

double x[maxn+5],y[maxn+5];

inline double dis(const int i,const int j){
    return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}

signed main(){
    while(~scanf("%d%d",&n,&m)){
        rep(i,1,n)scanf("%lf%lf",&x[i],&y[i]);
        G.Init(n);
        int u,v;
        rep(i,1,m){
            scanf("%d%d",&u,&v);
            if(u==v)continue;
            G.insert(u,v,dis(u,v));
        }double ans=G.launch(1);
        if(ans<0)puts("poor snoopy");
        else printf("%.2f\n",ans);
    }
    return 0;
}
posted @ 2020-09-24 21:44  Arextre  阅读(128)  评论(0编辑  收藏  举报