P4160 [SCOI2009]生日快乐[dfs]

题目描述

windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕。

现在包括windy,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的蛋糕。

windy主刀,每一切只能平行于一块蛋糕的一边(任意一边),并且必须把这块蛋糕切成两块。

这样,要切成 N 块蛋糕,windy必须切 N-1 次。

为了使得每块蛋糕看起来漂亮,我们要求 N 块蛋糕的长边与短边的比值的最大值最小。

你能帮助windy求出这个比值么?

解析

这题使我深刻领悟到我有多菜。

结论:切的位置的坐标一定是\(X/N\)\(Y/N\)的整数倍。

证明:用反证法。若某一刀切出的短边比\(X/N\)小,那么一定需要一个比\(Y\)还长的长边才能满足题目要求,显然不能切。

若某一刀切得比\(X/N\)大,比如切出来一个\(X/N+k,k<X/N\),那么切出来的这块矩形的长边一定小于\(Y\)且大于\(Y*(N-1)/N\),这样就会余出来一段\(p\),且\(0<p<Y/N\)。然而为了满足题目条件,我们势必要使\(p\)构成的矩形面积也等于\(X*Y/N\),但是它最大也就是\(p*X\),显然\(p*X<X*Y/N\),这是不可能的。

证毕。

明白这一点之后这题就简单了,但是我是个连深搜都写不对的菜鸡。

显然切一刀会分成两个子问题,而每次我们可以在所有合法位置横纵切。选择子问题所有情况中最大值最小的情况进行回溯即可。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 101
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
	int f=1,x=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
double n;
double x,y,kx,ky;
inline double dfs(double k,double nx,double ny)
{
	if(k==1){
		if(nx<ny) swap(nx,ny);
		return nx/ny;
	}
	double ans=INF,t1,t2;
	double kx=nx/k,ky=ny/k;
	for(int i=1;i<=k/2;++i){
		t1=max(dfs(k-i,nx-i*kx,ny),dfs(i,i*kx,ny));
		t2=max(dfs(k-i,nx,ny-i*ky),dfs(i,nx,i*ky));
		ans=min(ans,min(t1,t2));
	}
	return ans;
}
int main()
{
	cin>>x>>y>>n;
	printf("%.6lf",dfs(n,x,y));
	return 0;
}
posted @ 2019-10-22 19:52  DarkValkyrie  阅读(110)  评论(0编辑  收藏  举报