最小树形图

最小树形图学习笔记

直接上代码吧

#include<bits/stdc++.h>
using namespace std;
const int maxn=109;
const int oo=1000000000;

int n,m,r;
int w[maxn][maxn];

int flag[maxn];
int pre[maxn],vis[maxn];

int Mst(){
    int ans=0;
    
    for(;;){
        for(int i=1;i<=n;++i){
            if(i==r||flag[i])continue;
            w[i][i]=oo;pre[i]=i;
            for(int j=1;j<=n;++j){
                if(flag[j])continue;
                if(w[j][i]<w[pre[i]][i])pre[i]=j;
            }
            if(pre[i]==i)return -1;
        }
        
        int beg=0;
        for(beg=1;beg<=n;++beg){
            if(beg==r||flag[beg])continue;//!!!!!!
            int x=beg,cnt=0;
            while(x!=r&&pre[x]!=beg&&cnt<=n){
                x=pre[x];++cnt;
            }
            if(x==r||cnt>n)continue;
            break;
        }
        if(beg>n){
            for(int i=1;i<=n;++i){
                if(i!=r&&!flag[i]){
                    ans+=w[pre[i]][i];
                }
            }
            return ans;
        }
        
        int x=beg;
        memset(vis,0,sizeof(vis));
        for(;;){
            ans+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
            if(x==beg)break;
        }
        flag[beg]=0;
        
        for(int i=1;i<=n;++i){
            if(!vis[i])continue;
            for(int j=1;j<=n;++j){
                if(vis[j])continue;
                if(w[i][j]<w[beg][j])w[beg][j]=w[i][j];
                if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][beg]){
                    w[j][beg]=w[j][i]-w[pre[i]][i];
                }
            }
        }
    }
    return ans;
}
int main(){
    scanf("%d%d%d",&n,&m,&r);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=n;++j){
            w[i][j]=oo;
        }
    }
    while(m--){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x!=y){
            w[x][y]=min(w[x][y],z);
        }
    }
    printf("%d\n",Mst());
    
    return 0;
}

BZOJ 4349 最小树形图

题解:显然是所有的堡垒先都打完一遍,

然后还有需要打的堡垒就用入边权值最小的代价打

求打完一遍的权值和

建立虚点root,向1-n连边

然后再连好读入的边,跑最小树形图就可以了

#include<bits/stdc++.h>
using namespace std;

const int maxn=109;
const int oo=1000000000;

int n,m,root;
double ans=0;
double A[maxn];int B[maxn];
double w[maxn][maxn];

double minedge[maxn];

int flag[maxn];
int vis[maxn],pre[maxn];

double Mst(){
    double ret=0;
    
    for(;;){
        for(int i=1;i<=n;++i){
            if(i==root||flag[i])continue;
            w[i][i]=oo;pre[i]=i;
            for(int j=1;j<=n;++j){
                if(flag[j])continue;
                if(w[j][i]<w[pre[i]][i])pre[i]=j;
            }
        }
        
        int beg;
        for(beg=1;beg<=n;++beg){
            if(beg==root||flag[beg])continue;
            int x=beg,cnt=0;
            while(x!=root&&pre[x]!=beg&&cnt<=n){
                x=pre[x];++cnt;
            }
            if(x==root||cnt>n)continue;
            break;
        }
        
        if(beg>n){
            for(int i=1;i<=n;++i){
                if(!flag[i]&&i!=root){
                    ret+=w[pre[i]][i];
                }
            }
            return ret;
        }
        
        int x=beg;
        memset(vis,0,sizeof(vis));
        for(;;){
            ret+=w[pre[x]][x];x=pre[x];vis[x]=flag[x]=1;
            if(x==beg)break;
        }
        flag[x]=0;
        
        for(int i=1;i<=n;++i){
            if(!vis[i])continue;
            for(int j=1;j<=n;++j){
                if(vis[j])continue;
                if(w[i][j]<w[x][j])w[x][j]=w[i][j];
                if(w[j][i]!=oo&&w[j][i]-w[pre[i]][i]<w[j][x])w[j][x]=w[j][i]-w[pre[i]][i];
            }
        }
    }
}

int main(){
//  freopen("fuck.in","r",stdin);
    
    scanf("%d",&n);
    root=n+1;
    for(int i=1;i<=n+1;++i){
        for(int j=1;j<=n+1;++j){
            w[i][j]=oo;
        }
    }
    for(int i=1;i<=n;++i){
        cin>>A[i]>>B[i];
        w[root][i]=A[i];
        minedge[i]=A[i];
    }
    
    scanf("%d",&m);
    while(m--){
        int x,y;double z;
        cin>>x>>y>>z;
        if(x!=y){
            w[x][y]=min(w[x][y],z);
        }
        minedge[y]=min(minedge[y],z);
    }
    n=n+1;
    ans+=Mst();
    for(int i=1;i<=n;++i)ans+=(B[i]-1)*minedge[i];
    printf("%.2f\n",ans);
    
    return 0;
}

转载于:https://www.cnblogs.com/zzyer/p/9283173.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值