二分算法入门题--POJ - 1905 和POJ - 3104

二次信任 提交于 2020-01-21 15:26:17

今天又重新回顾二分算法,觉着这两个题目的思路很好。附上一下。

poj-1905  几何+二分

链接:https://vjudge.net/problem/POJ-1905

题目大意

当长度为L的细杆被加热n度时,它扩展到一个新的长度L‘=(1+n*C)*L,其中C是热膨胀系数。当一根细杆安装在两个实心壁上,然后加热时,它就膨胀成一个圆形!!!的节段,原来的杆是节段的弦。你的任务是计算杆中心移位的距离。
每行输入包含三个非负数:杆的初始长度(毫米)、温度变化(以度计)和材料的热膨胀系数。输入数据保证任何杆都不会膨胀超过其原始长度的一半。最后一行输入包含三个负数,不应该进行处理。
然后输出该木棍的中心位移

 

解题思路:

集合画出来是酱紫的:

 

由上面那个图,可以得出如下关系:

R^2=(R-h)^2+L^2/4;

LL(弧长)=2*R*θ;

R*sin(θ)=1/2*L;

由上面三个式子可以推出:

R=(4*h^2+L^2)/(8*h);

LL=2*R*arcsin(L/(2*R));

又因为,0<=R<=L/2, h=R*(1-cos(θ));

所以 0<=h<=L/2,  利用二分枚举h,通过LL来进行更新。具体看代码。

#include<iostream>//二分枚举h(高度) 
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
double l,t,c;
const double Max=1e-8;//注意精度问题 
int main()
{
	while(1)
	{
		scanf("%lf%lf%lf",&l,&t,&c);
		if(l<0&&t<0&&c<0)break;
		double s=(1+t*c)*l;//弧长
		double head=l/2,tail=0,mid;
		double r;
		while((head-tail)>=Max){
			mid=(head+tail)/2;
			r=(4*mid*mid+l*l)/(8*mid);
			double cnt=2*r*asin(l/(2*r));
			if(cnt<=s)
			{
				tail=mid;
			}
			else head=mid;
		}
		printf("%.3f\n",tail);
	}
	return 0;
}

 

poj-3104 (思路很好)

链接:https://vjudge.net/problem/POJ-3104

 题目大意

有n件衣服,每件衣服有一个湿润度,有一个烘干机,每次可以烘干一件衣服,每分钟烘干k的水分,每分钟可以选择放入/拿出一件衣服,如果衣服没有放入烘干机那么衣服每分钟会自然蒸发1水分。问怎么才能将所有衣服烘干并且所花时间要最少,最少时间是多少。

思路

难点是如果不放入烘干机中衣服每分钟会自然蒸发1水分,那么有没有办法将自然蒸发这个条件去掉呢,其实还是可以

的,我们可以假设用了m分钟,那么自然烘干的水分就是每件衣服m的水分,剩下的水分就是使用烘干机烘干的。但是

每次枚举m分钟肯定会超时,那么就可以用到二分了,如果枚举出来的时间可以将衣服全烘干,那么就可以缩小时间,

如果不能就扩大时间,二分得到最后的答案。具体看代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
typedef long long ll;
const int INF=1e5+5;
ll n,k;
ll a[INF];
ll fun(ll x)
{
	ll i,sum=0;
	ll temp;
	for(i=1;i<=n;i++)
	{
		if(a[i]<=x)continue;
		else {
			temp=a[i]-x;//注意,烘干机烘干的水
			sum+=temp/(k-1);//减去自然烘干的
			if(temp%(k-1))sum++;
		}
	}
	if(sum<=x)return 1;
	else return 0;
}
int main()
{
	scanf("%lld",&n);
    ll i,j;
	ll sum=0;
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		sum=max(sum,a[i]);//取最大值
	}
	scanf("%lld",&k);
	if(k==1)
	{
		printf("%d",sum);
		return 0;
	}
	ll head=sum,tail=0,mid;
	while(head>=tail)
	{
		mid=(head+tail)/2;
		if(fun(mid)){
			head=mid-1;
		}
		else tail=mid+1;
	}
	printf("%lld",tail);
    return 0;	
} 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!