HDU 4756 && HDU 4126

两个题次小生成树的扩展题。

先prim求出最小生成树,枚举删除每条树边后求分割成的两部分之间的最小连接费用,这一步用一个O(n^2)的n遍dfs求解。

不过HDU 4756这个题我被sqrt函数卡死,之前的写法HDU被卡爆栈,給sqrt传负数爆栈

//double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);  
dis[i][j]=dis[j][i]=sqrt(tmp);


HDU 4756
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 1010
#define INF 0x3f3f3f3f
using namespace std;

int n,k;
int x[N],y[N];
double dis[N][N];

double d[N];
int vis[N];
bool mp[N][N];
double ans;

struct Edge{
    int v,next;
}edge[N*2];
int head[N],cnt;

double dp[N][N];

void init(){
    memset(head,-1,sizeof(head));
    cnt=0;
}

void addedge(int u,int v){
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

void prim(){
    for(int i=0;i<n;i++){
        vis[i]=0;
        d[i]=dis[0][i];
    }
    vis[0]=-1;
    ans=0;
    memset(mp,0,sizeof(mp));
    for(int i=1;i<n;i++){
        double Min=(double)INF;
        int node=-1;
        for(int j=0;j<n;j++){
            if(vis[j]!=-1 && d[j]<Min){
                node=j;
                Min=d[j];
            }
        }

        ans+=Min;
        mp[vis[node]][node]=mp[node][vis[node]]=1;
        addedge(vis[node],node);
        vis[node]=-1;

        for(int j=0;j<n;j++){
            if(vis[j]!=-1 && d[j]>dis[node][j]){
                vis[j]=node;
                d[j]=dis[node][j];
            }
        }
    }
}

double dfs(int cur,int u,int fa){
    double res=(double)INF;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        double tmp=dfs(cur,v,u);
        dp[u][v]=dp[v][u]=min(tmp,dp[u][v]);
        res=min(res,tmp);
    }
    if(fa!=cur){
        res=min(res,dis[cur][u]);
    }
    return res;
}

int main(){
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int t,T;
    scanf("%d",&T);
    for(t=1;t<=T;t++){
        scanf("%d %d",&n,&k);
        for(int i=0;i<n;i++){
            scanf("%d %d",&x[i],&y[i]);
        }
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                double tmp=(double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j]);
                //double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
                dis[i][j]=dis[j][i]=sqrt(tmp);
            }
        }
        init();
        prim();
        for(int i=0;i<n;i++)
            for(int j=i;j<n;j++)
                dp[i][j]=dp[j][i]=(double)INF;
        for(int j=0;j<n;j++)
            dfs(j,j,-1);
        double ANS=ans;   //这里一定要初始化为ans
        //printf("%lf\n",ans);
        for(int i=1;i<n;i++){
            for(int j=i+1;j<n;j++){
                if(mp[i][j]){
                    ANS=max(ANS,ans-dis[i][j]+dp[i][j]);
                }
            }
        }
        printf("%.2lf\n",ANS*k);
    }
    return 0;
}

HDU 4126

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 3010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n,m;
int dis[N][N];

int d[N];
int vis[N];
bool mp[N][N];
ll ans;

struct Edge{
    int v,next;
}edge[N*2];
int head[N],cnt;

int dp[N][N];

void init(){
    memset(head,-1,sizeof(head));
    cnt=0;
}

void addedge(int u,int v){
    edge[cnt].v=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}

void prim(){
    for(int i=0;i<n;i++){
        vis[i]=0;
        d[i]=dis[0][i];
    }
    vis[0]=-1;
    ans=0;
    memset(mp,0,sizeof(mp));
    for(int i=1;i<n;i++){
        int Min=INF;
        int node=-1;
        for(int j=0;j<n;j++){
            if(vis[j]!=-1 && d[j]<Min){
                node=j;
                Min=d[j];
            }
        }

        ans+=Min;
        mp[vis[node]][node]=mp[node][vis[node]]=1;
        addedge(vis[node],node);
        vis[node]=-1;

        for(int j=0;j<n;j++){
            if(vis[j]!=-1 && d[j]>dis[node][j]){
                vis[j]=node;
                d[j]=dis[node][j];
            }
        }
    }
}

int dfs(int cur,int u,int fa){
    int res=INF;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa)continue;
        int tmp=dfs(cur,v,u);
        dp[u][v]=dp[v][u]=min(tmp,dp[u][v]);
        res=min(res,tmp);
    }
    if(fa!=cur){
        res=min(res,dis[cur][u]);
    }
    return res;
}

int main(){
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int u,v,w;
    while(scanf("%d %d",&n,&m)){
        if(n==0 && m==0)break;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++) dis[i][j]=INF;
        for(int i=0;i<m;i++){
            scanf("%d %d %d",&u,&v,&w);
            dis[u][v]=dis[v][u]=w;
        }
        init();
        prim();
        for(int i=0;i<n;i++)
            for(int j=i;j<n;j++)
                dp[i][j]=dp[j][i]=INF;
        for(int j=0;j<n;j++)
            dfs(j,j,-1);
        ll ANS=0;
        //printf("%lf\n",ans);
        int q;
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            scanf("%d %d %d",&u,&v,&w);
            if(!mp[u][v]) ANS+=ans;
            else ANS+=ans-dis[u][v]+min(w,dp[u][v]);
        }
        printf("%.4lf\n",(double)ANS/q);
    }
    return 0;
}




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值