最小乘积生成树
题目解析
想法还是比较难想到的。
把每棵生成树的和看成点对,于是答案是最小的点对。由于边权都是非负数,所以可以看成是离坐标轴最近的反比例函数的系数。
怎么求这个点呢?
首先,分别找到离轴,轴最近的点
这个可以分别以作为边权,求
不妨设离轴最近的点是,离轴最近的点是
然后,找到一个在左下方,并且离最远的点
可以等价为最大,因为底为是定值,三角形面积越大,高越大,而高就是距离。
根据叉乘的几何意义,
注意到是负数:(我还想了很久为啥它是负数,我一直以为叉乘顺序不一样(旋转方向不一样)只会影响最后生成的向量的方向(右手螺旋定理),但注意这里是有向面积)
如果是,那么就是逆时针转到,转了优角,所以,所以
反之,如果是,就是逆时针转到,转了劣角,所以乘出来
(图片来自于网络)
所以,要最大化,只需要最小化
根据叉乘的坐标表达形式:
后面是常数,所以要最小化,是生成树的,所以把边权赋成和,然后求就可以得到的坐标,用的坐标更新答案。
递归AC,BC
把拿去重复上述操作,递归处理,不断得到一个新的,更新答案。
直到算出来的满足,说明转过火了,这个时候的在上方,结束递归。
点的编号居然是从开始的,差评(雾
►Code View
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
#define N 205
#define M 10005
#define INF 0x3f3f3f3f
#define LL long long
int rd()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f*x;
}
int n,m,f[N];
struct node{
int u,v,a,b,w;
}e[M];
struct Point{
int x,y;
};
Point ans;
int Cross(Point p,Point q)
{
return p.x*q.y-p.y*q.x;
}
bool cmp(node p,node q)
{
return p.w<q.w;
}
void Init()
{
for(int i=1;i<=n;i++)
f[i]=i;
}
int Find(int x)
{
if(f[x]==x) return x;
return f[x]=Find(f[x]);
}
bool Union(int u,int v)
{
u=Find(u),v=Find(v);
if(u==v) return 0;
if(u<v) f[u]=v;
else f[v]=u;
return 1;
}
Point Kruskal()
{
Point res; res.x=0,res.y=0;
Init();
sort(e+1,e+m+1,cmp);
int cnt=0;
for(int i=1;i<=m;i++)
{
if(!Union(e[i].u,e[i].v)) continue;
res.x+=e[i].a,res.y+=e[i].b;
cnt++;
if(cnt==n-1) break;
}
LL ret=1ll*ans.x*ans.y,now=1ll*res.x*res.y;
if(now<ret||(now==ret&&res.x<ans.x)) ans=res;
return res;
}
void solve(Point A,Point B)
{
for(int i=1;i<=m;i++)
e[i].w=(B.x-A.x)*e[i].b+(A.y-B.y)*e[i].a;
Point C=Kruskal();
Point D,E;
D.x=B.x-A.x,D.y=B.y-A.y;
E.x=C.x-A.x,E.y=C.y-A.y;
if(Cross(D,E)>=0) return ;
solve(A,C);
solve(C,B);
}
int main()
{
n=rd(),m=rd();
for(int i=1;i<=m;i++)
e[i].u=rd()+1,e[i].v=rd()+1,e[i].a=rd(),e[i].b=rd();
for(int i=1;i<=m;i++)
e[i].w=e[i].a;
ans.x=INF,ans.y=INF;
Point A=Kruskal();
for(int i=1;i<=m;i++)
e[i].w=e[i].b;
Point B=Kruskal();
solve(A,B);
printf("%d %d\n",ans.x,ans.y);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现