BZOJ2395: [Balkan 2011]Timeismoney
乘积规划…神犇称其为隐式自适应凸包…
设每棵生成树为坐标系上的一个点,sigma(x[i])为横坐标,sigma(y[i])为纵坐标。则问题转化为求一个点,使得xy=k最小。
注意到这是一个反比例函数。所以显然的,有可能成为最优解的点集是一个凸包。
首先找到x最小的点A与y最小的点B,再找到离AB最远的点C,形成了一个三角形,这个三角形内部的点不可能成为最优答案(最优解的点集是一个凸包),所以我们继续递归AC,CB即可,对于找到的每一个点C尝试更新答案即可。
photo
怎么找到离一条直线最远的点呢?因为C离AB最远,所以S△ABC面积最大。即向量AB与向量AC的叉积最小(因为叉积是有向面积,是负数,所以取最小)
最小化:(B.x-A.x)(C.y-A.y)-(B.y-A.y)(C.x-A.x)
=(B.x-A.x)C.y+(A.y-B.y)*C.x - A.y(B.x-A.x)+A.x(B.y-A.y)
后面部分是常数,也就是最小化前面的部分。
将每条边的边权e[i].w设为e[i].t*(a.y-b.y)+e[i].c*(b.x-a.x);跑一遍最小生成树即可。
当叉积为正时,就是找不到一个那样的C点,return即可
有一个小技巧,kruskal记录下当前已经合并了的联通块的个数,是个小常数剪枝。还是比较有用的。
复杂度我也不知道…>_<…因为凸包上的点不会很多,所以速度应该还不错…如果谁能证明求告知…
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
//by:MirrorGray
using namespace std;
const int N=211111;
int n,m,fa[N];
struct P{int x,y;P(int a=0,int b=0){x=a;y=b;}P operator -(const P&b){return P(x-b.x,y-b.y);}friend int X(const P&a,const P&b){return a.x*b.y-a.y*b.x;}bool operator <(const P&b)const{if(x*y!=b.x*b.y)return x*y<b.x*b.y;return x<b.x;}void op(){printf("%d %d\n",x,y);}
}ans;
struct edge{int a,b,t,c,w;void read(){scanf("%d%d%d%d",&a,&b,&t,&c);a++;b++;}bool operator <(const edge&b)const{return w<b.w;}
}e[N];int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);
}P kruskal(){P ret;int tmp=0;sort(e+1,e+1+m);for(int i=1;i<=n;i++)fa[i]=i;for(int i=1;i<=m&&tmp<n-1;i++){int fx=find(e[i].a),fy=find(e[i].b);if(fx==fy)continue;tmp++;fa[fx]=fy;ret.x+=e[i].t;ret.y+=e[i].c;}ans=min(ans,ret);return ret;
}void solve(P a,P b){for(int i=1;i<=m;i++)e[i].w=e[i].t*(a.y-b.y)+e[i].c*(b.x-a.x);P c=kruskal();if(X(b-a,c-a)>=0)return ;solve(a,c);solve(c,b);
}int main(){scanf("%d%d",&n,&m);ans=P(40000,40000);for(int i=1;i<=m;i++)e[i].read();for(int i=1;i<=m;i++)e[i].w=e[i].t;P t1=kruskal();for(int i=1;i<=m;i++)e[i].w=e[i].c;P t2=kruskal();solve(t1,t2);ans.op();return 0;
}
BZOJ2395: [Balkan 2011]Timeismoney相关推荐
- 【BZOJ 2395】 [Balkan 2011]Timeismoney
2395: [Balkan 2011]Timeismoney Time Limit: 10 Sec Memory Limit: 128 MB Submit: 304 Solved: 169 [Subm ...
- 【BZOJ】2395: [Balkan 2011]Timeismoney
题解 最小乘积生成树! 我们把,x的总和和y的总和作为x坐标和y左边,画在坐标系上 我们选择两个初始点,一个是最靠近y轴的A,也就是x总和最小,一个是最靠近x轴的B,也就是y总和最小 连接两条直线,在 ...
- 微软CRM 2011 新功能之三:可新增客户化活动类型实体
微软CRM4.0标准功能提供任务.传真 .电话联络.电子邮件.手机短信.约会.服务活动和市场活动响应等8种活动类型,除此之外无法 新增客户化的活动类型,随着社会的发展已经无法满足现代商业业务的需求,比 ...
- [Buzz.Today]2011.05.25
>> VMWare的Open Source Pass - CloudFoundry VMWare推出了开源Pass:CloudFoundary,但是现在只是支持少数几种语言与环境:Java ...
- BZOJ 2440: [中山市选2011]完全平方数 [容斥原理 莫比乌斯函数]
2440: [中山市选2011]完全平方数 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 3028 Solved: 1460 [Submit][S ...
- 重新开始 2011/11/25
在csdn上写过几篇文章,始终没有坚持下来,也是由于自己没有一个明确的目标的缘故:当自己感觉乱的时候,总是想改变点东西,重新开始,改变了博客类的东西就真的能重新开始吗?现在我想换个博客就换个博客,这是 ...
- [scrum]2011/9/22-----第二天
scrum 总结: Team member Yesterday's Work Today's Work Issue R X Task196:Completed xml 文件的解析,并且通过了两个测试用 ...
- 参与2011年7月13日举行的Azure国际猜拳锦标赛,赢取5,000美元大奖
你想要编写自己的"bot"角色并测试你的技能,在线同来自美国,加拿大,中国,德国,新西兰,瑞典和英国的Windows Azure开发者一教高下,并赢取5,000美元大奖吗?请先注册 ...
- 靠数学“拿了”两次诺贝尔奖,彭罗斯从“铺地砖”帮忙发现2011年化学奖的秘密...
晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI 诺贝尔奖没有数学奖,但是如果数学足够好的话,可以拿两次诺贝尔奖: 帮别人拿一次,自己再拿一次. 刚刚获得诺贝尔奖的英国数学家罗杰·彭罗斯( ...
最新文章
- 微服务架构的优势与不足
- jsp mysql 判断连接数据库失败 try_急……jsp 连接mysql不知道哪里出异常
- 核心期刊 CA JST CSCD 含金量_期刊评介|《仪表技术与传感器》科技期刊的阿玛尼,只管投就对了!...
- Nginx安装手冊以及图片server部署
- Python之Time模块
- Python 爬虫十六式 - 第六式:JQuery的假兄弟-pyquery
- 复制Oracle表的结构
- .net的retrofit--WebApiClient底层篇
- [翻译]运用文件解析器在任意文件中使用虚拟应用路径(~)
- 公司申请了网易企业电子邮箱,用手机端办公方便吗?
- 协议圣经(二) RTP组播音视频技巧
- Ubuntu 12.04 下安装 Eclipse
- 【FPGA的基础快速入门22-------OV7725摄像头模块】
- 无盘服务器易乐游,网维大师、易乐游无盘万兆性能评测
- canvas学习之-七色板
- 地方棋牌游戏里的家乡情结
- html写樱花树,写樱花树的作文
- 2.5D地图GIS系统技术方案
- FS116B FS 0.55A电流输出单通道玩具直流马达驱动器
- python freshman day2