博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj2395[Balkan 2011]Timeismoney最小乘积生成树
阅读量:4946 次
发布时间:2019-06-11

本文共 3736 字,大约阅读时间需要 12 分钟。

所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值。

直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也就不难想到将生成树转化为平面内的点,x代表Σxi,y代表Σyi(注意这里的xi,yi指的是在生成树中的边的权值),那么问题就变成了在平面内找一个点使得x*y最小,那么显然这个点是在下凸壳上的。

因此可以首先找出两个一定在凸包上的点,例如A(minx,y),B(miny,x),在直线AB下方找一个在凸包上且x*y最小的点。

于是可以每次找距离直线AB最远的点,有两种求法,令找到的那个点为C,如果利用叉乘,即使向量CB叉乘向量CA最大,因为我们考虑的是向量的模长,可以让向量CA叉乘向量CB(虽然模长是负的,但并没有什么关系,当然也可以最大化这个值,只不过一个是最小生成树,一个是最大生成树而已),然后最小化这个值即可。

2S=(B.x-A.x)(C.y-B.y)-(B.y-A.y)(C.x-A.x)省略常数后就变成了B.x*C.y-A.x*C.y-B.y*C.x+A.y*C.x。

因为只需要求Σxi,Σyi,因此只需要求出点的坐标,并不要考虑面积,所以将每条边的yi=yi*(B.x-A.x),xi=xi*(A.y-B.y),以(xi+yi)为关键字排序kruskal()就行了。

然后递归处理,直到叉积大于等于0退出(此时AB下方一定没有点)

也可以利用点到直线的距离公式|Ax0+By0+C|/(√(A2+B2)),省略常数且保证B<=0,那么若点在直线下方,则Ax+By+C>0。

因此可以省略绝对值符号,再省略常数,即使Ax0+By0最大,因此xi=xi*A,yi=yi*B,将(xi+yi)为关键字排序作最大生成树即可,还是按叉积判断(理应也可以看C.x*A+C.y*B<=0就退出,然而狂WA不止。。。。并不知道这是为什么。。。。)

然后这是一道裸题,就可以愉快地切掉了。

1 #include
2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 #define maxn 10100 8 #define inf 0x7fffffff 9 10 int n,m;11 int val[2*maxn],fa[maxn];12 13 struct edge{14 int from,to,x,y;15 long long z;16 }e[maxn];17 18 struct node{19 int x,y;20 long long calc(){
return (long long)x*y;}21 }minx,miny,ans;22 23 int find(int x){24 return fa[x]==x?x:fa[x]=find(fa[x]);25 }26 27 node kruskal(){28 int tot=0;node now={
0,0};29 for (int i=1;i<=n;i++) fa[i]=i;30 for (int i=1;i<=m;i++){31 int a=find(e[i].from),b=find(e[i].to);32 if (a!=b){33 fa[a]=b;34 tot++;35 now.x+=e[i].x;36 now.y+=e[i].y;37 if (tot==n-1) break;38 }39 }40 long long tmpa=ans.calc(),tmpb=now.calc();41 if (tmpb
=0) return;60 solve(a,t);61 solve(t,b);62 }63 64 int main(){65 scanf("%d%d",&n,&m);66 ans=(node){inf,inf};67 for (int i=1,u,v;i<=m;i++) scanf("%d%d%d%d",&u,&v,&e[i].x,&e[i].y),e[i].from=++u,e[i].to=++v;68 sort(e+1,e+m+1,cmpx);69 minx=kruskal();70 sort(e+1,e+m+1,cmpy);71 miny=kruskal();72 //cout<
<<' '<
<<' '<
<<' '<
<
View Code1
1 #include
2 #include
3 #include
4 #include
5 #include
6 using namespace std; 7 #define maxn 10100 8 #define inf 0x7fffffff 9 10 int n,m;11 int val[2*maxn],fa[maxn];12 13 struct edge{14 int from,to,x,y;15 long long z;16 }e[maxn];17 18 struct node{19 int x,y;20 long long calc(){
return (long long)x*y;}21 }minx,miny,ans;22 23 int find(int x){24 return fa[x]==x?x:fa[x]=find(fa[x]);25 }26 27 node kruskal(){28 int tot=0;node now={
0,0};29 for (int i=1;i<=n;i++) fa[i]=i;30 for (int i=1;i<=m;i++){31 int a=find(e[i].from),b=find(e[i].to);32 if (a!=b){33 fa[a]=b;34 tot++;35 now.x+=e[i].x;36 now.y+=e[i].y;37 if (tot==n-1) break;38 }39 }40 long long tmpa=ans.calc(),tmpb=now.calc();41 if (tmpb
b.z;}53 54 void solve(node a,node b){55 int A=b.y-a.y,B=a.x-b.x;56 for (int i=1;i<=m;i++) e[i].z=e[i].x*A+e[i].y*B;57 sort(e+1,e+m+1,cmpz);58 node t=kruskal();59 if (cross(a,b,t)<0) solve(a,t),solve(t,b);60 }61 62 int main(){63 // freopen("data.in","r",stdin);64 // freopen("WA.out","w",stdout);65 scanf("%d%d",&n,&m);66 ans=(node){inf,inf};67 for (int i=1,u,v;i<=m;i++) scanf("%d%d%d%d",&u,&v,&e[i].x,&e[i].y),e[i].from=++u,e[i].to=++v;68 sort(e+1,e+m+1,cmpx);69 minx=kruskal();70 sort(e+1,e+m+1,cmpy);71 miny=kruskal();72 //cout<
<<' '<
<<' '<
<<' '<
<
View Code2

转载于:https://www.cnblogs.com/DUXT/p/5739864.html

你可能感兴趣的文章
opencv 识别微信登录验证滑动块位置
查看>>
爬虫相关汇总
查看>>
时间序列数据库调研之InfluxDB
查看>>
VIP之CSC
查看>>
题解 UVA1555 【Garland】(二分)
查看>>
C语言strchr()函数:查找某字符在字符串中首次出现的位置
查看>>
关于设置SQLPLUS提示符样式的方法----登陆配置文件,动态加载提示符
查看>>
ORACLE和SQL SERVER的数据同步常用方法
查看>>
webclinet downstring 搜狐 为什么是个?号
查看>>
Mybatis框架 使用接口Mapper实现数据库的crud操作
查看>>
Android SDCard Mount 流程分析(二)
查看>>
java基础---HashMap和HashTable的异同之处
查看>>
人物-发明家-贝尔:亚历山大·贝尔
查看>>
HTTP-Runoob:HTTP状态码
查看>>
声屏障:声屏障
查看>>
CSS3:教程
查看>>
.NETFramework-Web.Mvc:HttpNotFoundResult
查看>>
断言类
查看>>
VS2008 analyze 启动分析 蓝屏 解决
查看>>
html + css3 demo
查看>>