网络战争

本文深入探讨了在处理大规模地理坐标数据时,如何运用KD-Tree、最小割树(Gomory Tree)及倍增算法解决首府间最近点连接问题,并通过详细代码示例阐述了算法的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PDF题面

我曾经以为$LCT$已经足够毒瘤,直到我写了树套树。

我曾经又以为树套树已经足够毒瘤,直到我写了这道题。

$hhh$

这道题大概分为三个部分

 

一、首府之间最近点相连

由于$N$不超过$10^5$,且$|X_i|,|Y_i|$均匀随机,我们大可以使用$KD-Tree$,即先以每个州首府坐标建出$KD-Tree$,再枚举每一个点进行在$KD-Tree$中搜索,由于坐标随机,复杂度期望为$O(N\log N)$。

这里有一个性质,那就是一定不存在重边以外的简单环。因为如果存在,那么你一定能找到一个不符合要求的点,所以这样连出来的一定是树或森林。如果有重边,那么很显然若我们要割掉它,必须把两条边全部割掉,即把所有重边变成一条边,这条新的边权值是原来重边的和。并且在后续计算答案时,若两个点所在的州不在同一个连通块上,那么答案为$0$,因为本身就不联通,这个用并查集维护即可。

 

二、预处理最小割树$(Gomory\space Tree)$

最小割树基于一个非常重要的理论:在$n$个点的无向图中,本质不同的割至多有$n-1$个。利用这个性质,我们可以将这个无向图重构成一棵树,每一条树边代表一种割的方案的代价。

具体的方法就是,设一开始所有的点都在同一个点集中,然后随便选一个点数大于$1$的点集$S$,从$S$中任取两点$a,b$,以$a,b$为源汇跑最小割,然后把$S$中和$a$在割集同一侧的点单独拿出来,$S$中剩下的点一定和$b$在割集的同一侧,这样产生了两个$S$的非空子集$S_1,S_2$,并且在重构的树上建立一条$(a,b)$权值为割集大小的树边,然后将$S_1,S_2$递归处理直到$|S|=1$为止,这样,任意两个点最小割就是在重构树上两个点的路径上最小的边权。虽然说这样的复杂度可能达到$O(Dinic\sum n_i^2)$这道题并没有其他更可行的做法......,不过在我写到这里的时候,隔壁的$julao$ Mys_C_K 走了过来告诉我这个复杂度是可以用均值不等式来证明在$Dinic$够快的情况下是合法的。

 

三、大小树跑倍增

大树就是每一个首府连成的树,小树就是每个州内部的最小割树,只是用倍增维护一下路径最小值而已,非常简单,没啥可说的。

 

来吧,面对疾风吧。

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define mid ((l+r)>>1)
#define INF 1000000000
#define N 100200
#define HA main
using namespace std;
namespace IO{
    const int SS=(1<<20)+5;
    char buf[SS],*H,*K;
    inline char Get(){
        if(H==K) K=(H=buf)+fread(buf,1,SS,stdin);
        if(H==K) return -1;return *H++;
    }
    inline int read(){
        int x=0,fg=1;char c=Get();
        while(!isdigit(c)&&c!='-') c=Get();
        if(c=='-') fg=-1,c=Get();
        while(isdigit(c)) x=x*10+c-'0',c=Get();
        return x*fg;
    }
    char obuf[SS],*oS=obuf,*oT=oS+SS-1,c,qu[55];int qr;
    inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
    inline void putc(char x){*oS++ =x;if(oS==oT) flush();}
    void print(int x){
        if(!x) putc('0');
        if(x<0) putc('-'),x=-x;
        while(x) qu[++qr]=x%10+'0',x/=10;
        while(qr) putc(qu[qr--]);
        putc('\n');
    }
}
using namespace IO;
int sq(int x){return x*x;}
int n,m,fs[N],nt[N<<1],to[N<<1],len[N<<1],dt[N],ot[N],vis[N],kd;
int u[N<<6],v[N<<6],w[N<<6],V[N][2],E[N][2],tmp,now;
int res[N],G[N][18],P[N][18],D[N];
struct node{
    int id,c[2]; node(){}
    node(int _id,int _c0,int _c1){id=_id,c[0]=_c0,c[1]=_c1;}
    void gtin(int x){c[0]=read(),c[1]=read(),id=x;}
    bool operator <(const node&ot)const{return c[kd]<ot.c[kd];}
}p[N];
int dst(node x,node y){return sq(x.c[0]-y.c[0])+sq(x.c[1]-y.c[1]);}
struct TREE{
    int mi[N][2],mx[N][2],cnt,t[N],fa[N][18],F[N],W[N][18],L[N],R[N];
    int fst[N],nxt[N<<1],gto[N<<1],val[N],dis[N<<1],TMP,dep[N],Root;
    int fd(int x){return F[x]==x?x:F[x]=fd(F[x]);}
    void gt(int x,node k){mx[x][0]=mi[x][0]=k.c[0],mx[x][1]=mi[x][1]=k.c[1];}
    void iit(){cnt=TMP=0,memset(fst,-1,sizeof(fst)),memset(W,0x3f,sizeof(W));}
    int mind(int x,node k){
        if(!x) return INF; int tt=0;
        for(int i=0;i<2;i++){
            if(k.c[i]<mi[x][i]) tt+=sq(mi[x][i]-k.c[i]);
            else if(k.c[i]>mx[x][i]) tt+=sq(mx[x][i]-k.c[i]);
        }
        return tt;
    }
    void update(int x,int from){
        if(from==0) return;
        mx[x][0]=max(mx[x][0],mx[from][0]),mx[x][1]=max(mx[x][1],mx[from][1]);
        mi[x][0]=min(mi[x][0],mi[from][0]),mi[x][1]=min(mi[x][1],mi[from][1]);
    }
    void pushup(int x){gt(x,p[t[x]]),update(x,L[x]),update(x,R[x]);}
    void build(int &x,int l,int r,int nw){
        x=++cnt,L[x]=R[x]=0;
        m=nw,nth_element(p+l,p+mid,p+r+1);t[x]=mid,gt(x,p[t[x]]);
        if(l<mid) build(L[x],l,mid-1,nw^1),update(x,L[x]);
        if(mid<r) build(R[x],mid+1,r,nw^1),update(x,R[x]);
    }
    void query(int x,int ps){
        if(!x) return;
        if(t[x]!=ps){
            int t1=dst(p[ps],p[t[x]]);
            if(t1<dt[p[ps].id]) dt[p[ps].id]=t1,ot[p[ps].id]=p[t[x]].id;
            else if(t1==dt[p[ps].id]&&p[t[x]].id<ot[p[ps].id]) ot[p[ps].id]=p[t[x]].id;
        }
        int t1=mind(L[x],p[ps]),t2=mind(R[x],p[ps]);
        if(t1<t2){if(t1<=dt[p[ps].id]) query(L[x],ps);if(t2<=dt[p[ps].id]) query(R[x],ps);}
        else{if(t2<=dt[p[ps].id]) query(R[x],ps);if(t1<=dt[p[ps].id]) query(L[x],ps);}
    }
    void lk(int x,int y,int Len){nxt[TMP]=fst[x],fst[x]=TMP,gto[TMP]=y,dis[TMP++]=Len;}
    void DFS(int x,int last,int from){
        fa[x][0]=last,dep[x]=dep[last]+1,W[x][0]=from;
        for(int j=1;j<18;j++){
            fa[x][j]=fa[fa[x][j-1]][j-1];
            W[x][j]=min(W[x][j-1],W[fa[x][j-1]][j-1]);
        }
        for(int i=fst[x];i!=-1;i=nxt[i])
            if(gto[i]!=last) DFS(gto[i],x,dis[i]);
    }
    void cover(){
        for(int i=1;i<=n;i++) fst[i]=-1,F[i]=i,query(Root,i);
        for(int i=1;i<=n;i++){
            if(i==ot[ot[i]]&&val[ot[i]]>0) val[ot[i]]+=val[i],val[i]=0;
            else lk(i,ot[i],val[i]),lk(ot[i],i,val[i]),F[fd(i)]=fd(ot[i]);
        }
        for(int i=1;i<=n;i++) if(fd(i)==i) DFS(i,0,0); 
    }
    int minn(int x,int y){
        if(fd(x)!=fd(y)) return 0;
        if(dep[x]<dep[y]) swap(x,y); int now=INF;
        for(int j=17;j>=0;j--){
            if(dep[fa[x][j]]<dep[y]) continue;
            now=min(now,W[x][j]),x=fa[x][j];
        }
        for(int j=17;j>=0;j--){
            if(fa[x][j]==fa[y][j]) continue;
            now=min(now,min(W[x][j],W[y][j]));
            x=fa[x][j],y=fa[y][j];
        }
        while(x!=y) now=min(now,min(W[x][0],W[y][0])),x=fa[x][0],y=fa[y][0];
        return now;
    }
    void RUN(){build(Root,1,n,0);cover();}
}Cap;
struct Gomory_tree{
    int cur[N],S,T,rem[N],q[N],hd,tl,tt[N],pos[N],col[N],tot,sz,nw;
    void addedge(int x,int y,int rm){
        nt[tmp]=fs[x],fs[x]=tmp,to[tmp]=y,rem[tmp++]=rm;
        nt[tmp]=fs[y],fs[y]=tmp,to[tmp]=x,rem[tmp++]=rm;
    }
    void init(int B){
        tot=E[B][1]-E[B-1][1],sz=V[B][1]-V[B-1][1];
        for(int i=1;i<=sz;i++) fs[i]=-1,pos[i]=i; tmp=0,nw=E[B][0];
        for(int i=E[B][0];i<=E[B][1];i++) addedge(u[i],v[i],w[i]);
    }
    bool BFS(){
        for(int i=1;i<=sz;i++) cur[i]=fs[i],vis[i]=-2;
        hd=tl=0,vis[S]=1,q[tl++]=S;
        while(hd<tl){
            int x=q[hd++];
            for(int i=fs[x];i!=-1;i=nt[i]){
                if(rem[i]==0||vis[to[i]]>=0) continue;
                vis[to[i]]=vis[x]+1,q[tl++]=to[i];
            }
        }
        return vis[T]>0;
    }
    int dfs(int x,int mxf){
        if(x==T||!mxf) return mxf;
        int temp=0; 
        for(int &i=cur[x];i!=-1;i=nt[i]){
            if(rem[i]==0||vis[to[i]]!=vis[x]+1) continue;
            int lc=min(mxf-temp,rem[i]); int rc=dfs(to[i],lc);
            rem[i]-=rc,rem[i^1]+=rc,temp+=rc;
            if(temp==mxf) break;
        }   
        if(temp==0) vis[x]=-2;
        return temp;
    }
    int dinic(){int as=0;while(BFS()) as+=dfs(S,INF);return as;}
    void clr(){
        for(int i=0,sum;i<tmp;i+=2) sum=rem[i]+rem[i+1],rem[i]=rem[i+1]=(sum>>1);
        for(int i=1;i<=sz;i++) col[i]=0;
    }
    void Paint(int x){
        if(col[x]) return;
        col[x]=1;
        for(int i=fs[x];i!=-1;i=nt[i]) if(rem[i]) Paint(to[i]);
    }
    void solve(int l,int r){
        if(l==r) return; clr();
        S=pos[l],T=pos[r],w[nw]=dinic();
        int t1=l,t2=r; u[nw]=S,v[nw]=T,nw++;
        Paint(S);
        for(int i=l;i<=r;i++){
            if(col[pos[i]]) tt[t1++]=pos[i];
            else tt[t2--]=pos[i];
        }
        for(int i=l;i<=r;i++) pos[i]=tt[i];
        solve(l,t2),solve(t1,r);
    }
    void check(int x){init(x),solve(1,sz);}
}Cut;
void getdep(int x,int last,int from){
    res[x]=min(res[last],from);
    P[x][0]=last,G[x][0]=from,D[x]=D[last]+1;
    for(int j=1;j<18;j++){
        P[x][j]=P[P[x][j-1]][j-1];
        G[x][j]=min(G[x][j-1],G[P[x][j-1]][j-1]);
    }
    for(int i=fs[x];i!=-1;i=nt[i]) if(to[i]!=last) getdep(to[i],x,len[i]);
}
int getans(int B1,int t1,int B2,int t2){
    if(Cap.fd(B1)!=Cap.fd(B2)) return 0;
    if(B1==B2){
        int fin=INF,x=t1+V[B1-1][1],y=t2+V[B1-1][1];
        if(D[x]<D[y]) swap(x,y);
        for(int j=17;j>=0;j--){
            if(D[P[x][j]]<D[y]) continue;
            fin=min(fin,G[x][j]),x=P[x][j];
        }
        for(int j=17;j>=0;j--){
            if(P[x][j]==P[y][j]) continue;
            fin=min(fin,min(G[x][j],G[y][j]));
            x=P[x][j],y=P[y][j];
        }
        if(x!=y) fin=min(fin,min(G[x][0],G[y][0]));
        return fin;
    }
    int fin=min(res[t1+V[B1-1][1]],res[t2+V[B2-1][1]]);
    return min(fin,Cap.minn(B1,B2));
}
int HA(){
    n=read(),memset(fs,-1,sizeof(fs));
    memset(dt,0x3f,sizeof(dt)),Cap.iit();
    for(int i=1;i<=n;i++){
        p[i].gtin(i),Cap.val[i]=read();
        V[i][0]=V[i][1]=V[i-1][1];E[i][0]=E[i][1]=E[i-1][1];
        V[i][0]++,E[i][0]++,V[i][1]+=read(),E[i][1]+=read(),res[V[i][0]]=INF;
        for(int j=E[i][0];j<=E[i][1];j++) u[j]=read(),v[j]=read(),w[j]=read();
    } Cap.RUN(),res[0]=INF;
    for(int i=1;i<=n;i++) Cut.check(i); memset(fs,-1,sizeof(fs)),tmp=0;
    for(int i=1;i<=n;i++){
        for(int j=E[i][0];j<E[i][0]+V[i][1]-V[i][0];j++){
            u[j]+=V[i-1][1],v[j]+=V[i-1][1];
            nt[tmp]=fs[u[j]],fs[u[j]]=tmp,to[tmp]=v[j],len[tmp++]=w[j];
            nt[tmp]=fs[v[j]],fs[v[j]]=tmp,to[tmp]=u[j],len[tmp++]=w[j];
        }
        getdep(V[i][0],0,INF);
    }
    for(int Q=read(),t1,t2,b1,b2,now;Q;Q--,tmp=0){
        b1=read(),b2=read(),t1=read(),t2=read();
        now=getans(b1,t1,b2,t2),print(now);
    }flush(); return 0;
}

 

转载于:https://www.cnblogs.com/OYJason/p/9688354.html

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值