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;
}
原文地址:https://www.cnblogs.com/DarkValkyrie/p/11722097.html