最小生成树系列QAQ

最简单的的最小生成树就不用说什么了…
总有一些神奇的“最小”的定义…(好烦人┗|`O′|┛)


No.1 最小乘积生成树

所谓最小乘积生成树指的是每条边有k个权值,生成树的代价为这里写图片描述
以k=2的情况为例:(多维的就是把线换成面)
送上题目链接一枚,请小心收好
我们把每一棵生成树看成二维平面上的一个点,Σw1看成横坐标,Σw2看成纵坐标…那么最小的定义就转化为了min(x*y)…也就是说每个点代表了一个反比例函数…很显然这个最优解一定存在于所有点的左下凸包上…
所以我们先找到最靠近x轴和最靠近y轴的两个点AB(这两个点一定是左下凸包上的点)…然后找到距离AB最远的靠近原点的C点(这个点也一定在凸包上)…然后再以AC、BC为界递归寻找凸包上的点…直到找不到点为止…


代码如下:
(说真心话这道题做了好久…[捂脸熊]…
首先是我忘记了有重边用了prim…
然后是AB设成了全局变量…)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200+5,maxm=10000+5;
int n,m,cnt,fa[maxn],node[3][2],tmp[3][2],ansa,ansb;
long long ans;
struct M{
    int x,y,t,c,w;
    friend bool operator < (M a,M b){
        return a.w<b.w;
    }
}s[maxm];
struct G{
    int x,y;
    G(int a=0,int b=0){
        x=a,y=b;
    }
};
inline int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline G kruskal(void){
    int cnt=0;G C;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++){
        int fx=find(s[i].x),fy=find(s[i].y);
        if(fx!=fy)
            fa[fx]=fy,cnt++,C.x+=s[i].t,C.y+=s[i].c;
        if(cnt==n-1)
            break;
    }
    long long now=C.x*C.y;
    if(ans>now||(ans==now&&C.x<ansa))
        ans=now,ansa=C.x,ansb=C.y;
    return C;
}
inline void solve(G A,G B){
    for(int i=1;i<=m;i++)
        s[i].w=s[i].c*(B.x-A.x)+s[i].t*(A.y-B.y);
    sort(s+1,s+m+1);G C=kruskal();
    if((B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x)>=0)
        return;
    solve(A,C);solve(C,B);
}
signed main(void){
    scanf("%d%lld",&n,&m);
    for(int i=1,x,y,a,b;i<=m;i++)
        scanf("%d%d%d%d",&s[i].x,&s[i].y,&s[i].t,&s[i].c),s[i].x++,s[i].y++;
    ans=inf;
    for(int i=1;i<=m;i++)
        s[i].w=s[i].t;
    sort(s+1,s+m+1);G A=kruskal();
    for(int i=1;i<=m;i++)
        s[i].w=s[i].c;
    sort(s+1,s+m+1);G B=kruskal();
    solve(A,B);printf("%d %d\n",ansa,ansb);
    return 0;
}

No2. 最小方差生成树

题目戳这里QAQ
题解戳这里QAQ


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
//by NeighThorn
using namespace std;
const int maxn=100+5,maxm=2000+5;
int n,m,fa[maxn];double Min;
struct M{
    int x,y,w;
    double ww;
    friend bool operator < (M a,M b){
        return a.ww<b.ww;
    }
}s[maxm];
inline int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline double kruskal(void){
    double ans=0,tot=0;int cnt=0;
    for(int i=1;i<=n;i++)
        fa[i]=i;
    for(int i=1;i<=m;i++){//cout<<s[i].x<<" "<<s[i].y<<endl;
        int fx=find(s[i].x),fy=find(s[i].y);
        if(fx!=fy)
            fa[fx]=fy,ans+=s[i].w*s[i].w,tot+=s[i].w,cnt++;
        if(cnt==n-1)
            break;
    }
    double ave0=tot/(double)(n-1);
    return ans-2.0*tot*ave0+(n-1.0)*ave0*ave0;
}
inline double calc(double ave){
    for(int i=1;i<=m;i++)
        s[i].ww=((double)s[i].w-ave)*((double)s[i].w-ave);
    sort(s+1,s+m+1);double tmp=kruskal();
    return sqrt(tmp/(double)(n-1));
}
signed main(void){
    scanf("%d%d",&n,&m);Min=1e10;int maxw=0;
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].w),maxw=max(maxw,s[i].w);
    maxw+=5;
    for(int i=0;i<=maxw*8;i++)
        Min=min(calc(i*0.125),Min);
    printf("%.4f\n",Min);
    return 0;
}

by >_< NeighThorn

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值