Gym - 100886D 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest D - Catenary

题目中有一句很迷幻的话:这是对双曲余弦函数的离散模拟
翻译成人话就是长成下图这样的图形就别考虑了,总体上还是和双曲余弦函数图像比较像的
在这里插入图片描述
双曲余弦函数在这种情况下也可以叫悬链线,很容易可以查到相关资料(不过对于这题没啥帮助)

根据题目的需求,把图形翻转一下得到向上垂的图形
因为铰链连接的木棍,在连接点上力的方向不一定沿杆的方向,所以需要对力的方向进行分析
下图黑色是木棍,红色是力的方向
在这里插入图片描述

记从x轴转到经过第i个点的力方向经过的夹角为 φ i \varphi_i φi,约定i从0开始,在这里的力的方向都是从标号小的点指向标号大的
(所以 φ \varphi φ会从正值逐渐变成负值)
考虑任意一段木棍(至少一根)只有两端的力是外力(在这里以上图4根棍举例,点标号0-4,棍标号1-4)
竖直方向: F sin ⁡ φ 0 − F sin ⁡ φ n = G [ 1 , 4 ] F\sin\varphi_0-F\sin\varphi_n=G_{[1,4]} Fsinφ0Fsinφn=G[1,4](G是重力)
因为每个连接点都平衡,则有 F i cos ⁡ φ i = c F_i\cos\varphi_i=c Ficosφi=c(c是常数)
用上面两条式子一除,就有 tan ⁡ φ 0 − tan ⁡ φ 4 = G [ 1 , 4 ] c \tan\varphi_0-\tan\varphi_4=\frac{G_{[1,4]}} c tanφ0tanφ4=cG[1,4]
(上式0,4可推广到任意两端点依然成立)
tan ⁡ φ i − tan ⁡ φ j = G [ i + 1 , j ] c \tan\varphi_i-\tan\varphi_j=\frac{G_{[i+1,j]}} c tanφitanφj=cG[i+1,j]

再考虑一下单个木棍的平衡,下图中蓝色是棍,红色是力的方向。
三力方向必共点,不然选择任两力交点作为支点,第三力到支点力矩不为0,木棍不平衡。
则结合木棍重心在中点的性质,可以很轻松地得到 tan ⁡ θ = tan ⁡ φ 1 + tan ⁡ φ 2 2 \tan\theta=\frac{\tan\varphi_1+\tan\varphi_2}{2} tanθ=2tanφ1+tanφ2
在这里插入图片描述

考虑一下怎么把两条式子合起来,很显然可以做差
tan ⁡ φ i − 1 − tan ⁡ φ n + tan ⁡ φ i − tan ⁡ φ n − 1 = tan ⁡ θ i − tan ⁡ θ n − 1 = ( G [ i , n ] + G [ i + 1 , n − 1 ] ) ∗ 2 c \tan\varphi_{i-1}-\tan\varphi_n+\tan\varphi_{i}-\tan\varphi_{n-1}=\tan\theta_i-\tan\theta_{n-1}=(G_{[i,n]}+G_{[i+1,n-1]})*\frac2c tanφi1tanφn+tanφitanφn1=tanθitanθn1=(G[i,n]+G[i+1,n1])c2

接下来这段感性认识一下
这东西翘的越高就会越窄,而角度都由首尾两个角决定。那么二分套二分,
在第一个角固定的前提下,最后一个角越翘,最后的点就会越高。
那么二分的目标就是让最后一个点回归水平
第一个角越翘,那么整体就会越窄
所以这个二分就是要让整体宽度接近L

二分后先把c算出来,再用上面那条式子依次算出每个角tan值即可

#include<stdio.h>
#include<cmath>
const double pi=acos(-1);

int n;
double g[15],l[15],L,Tan[15];

inline double sqr(double x){return x*x;}
inline double Sin(double Tan){return (Tan>0?1:-1)*sqrt(sqr(Tan)/(1+sqr(Tan)));}
inline double Cos(double Tan){return sqrt(1/(1+sqr(Tan)));}

inline double solve(double tan0,double tann)
{
	double c=(tan0-tann)/(g[n]-g[0]+g[n-1]-g[1]),rt=0;
	for (int i=1;i<=n;i++) 
		rt+=l[i]*Sin(Tan[i]=tann+c*(g[n]-g[i-1]+g[n-1]-g[i]));
	return rt;
}

inline double judge(double th0)
{
	double _l=-pi/2,_r=0,rt=0;
	for (int ts=0;ts<100;ts++)
	{
		double mid=(_l+_r)/2;
		if (solve(tan(th0),tan(mid))>0) _r=mid;
		else _l=mid;
	}
	for (int i=1;i<=n;i++) rt+=l[i]*Cos(Tan[i]);
	return rt;
}

int main()
{
	scanf("%d%lf",&n,&L);
	for (int i=1;i<=n;i++) scanf("%lf",l+i),g[i]=g[i-1]+l[i];
	double _l=0,_r=pi/2;
	for (int ts=0;ts<100;ts++)
	{
		double mid=(_l+_r)/2;
		if (judge(mid)<L) _r=mid;
		else _l=mid;
	}
	double x=0,y=0;
	for (int i=1;i<n;i++) printf("%.10lf %.10lf\n",x+=l[i]*Cos(Tan[i]),y+=l[i]*Sin(Tan[i]));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值