最小生成树+点乘原理

  • 点乘原理
    对于两个向量,最小向量点乘即为向量中最大的去乘另外一个向量中最小的,重复执行,最后的结果即为最小的
    image
  • 观察题意,易得二分答案p,再写一个check()函数即可
  • 在check过程中,对于损坏值小于p的路径,直接计入,求出最小生成树,最后记录最小生成树的边,使用点乘原理,以最有顺序修路。
    https://ac.nowcoder.com/acm/contest/52441/D
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,c,p;
int fa[2000010];
struct node{
    int st;
    int to;
    int cost;
    bool operator < (const node&a) const{
        return cost < a.cost;
    }
}edge[2000010];
int find(int x){
    if(fa[x]==x) return x;
    else{
        fa[x] = find(fa[x]);
        return fa[x];
    }
}
void merge(int x,int y){
    fa[find(x)] = find(y);
    return;
}
bool check(int number){
    for(int i = 1;i<=n;i++) fa[i] = i;
    int sum = 0;
    int ans[1000000];
    int cnt = 0;
    for(int i = 1;i<=m;i++){
        if(edge[i].cost<=number){
            merge(edge[i].st,edge[i].to);
            continue;
        }
        if(find(edge[i].st)!=find(edge[i].to)){
            merge(edge[i].st,edge[i].to);
            ans[++cnt] = edge[i].cost;
        }
    }
    sort(ans+1,ans+1+cnt);
    int op = 1;
    for(int i = cnt;i>=1;i--){
        sum += ans[i]*op;
        op++;
    }
    if(sum<=c) return true;
    else return false;
}
signed main(){
    cin>>n>>m>>c;
    int x,y,z;
    for(int i = 1;i<=m;i++){
        cin>>edge[i].st>>edge[i].to>>edge[i].cost;
    }
    sort(edge+1,edge+1+m);
    int l = 0;
    int r = 1e18;
    while(l<=r){
        int mid = (l+r)>>1;
        if(check(mid)) p = mid,r = mid-1;
        else l = mid+1;
    }
    cout<<p<<endl;
}
posted @ 2023-03-28 22:15  重生之我是菜鸟  阅读(32)  评论(0)    收藏  举报