题目一:
平衡负载(二分法)
Du熊正在负责一个大型的项目,目前有K台服务器,有N个任务需要用这K台服务器来完成,所以要把这些任务分成K个部分来完成,在同上台服务器上执行的任务必须是连续的任务,每个任务有各自需要的执行时间。
例如N=5,K=2,每个任务需要时间分别为5,3,1,4,7分钟,那么我们可以分成(5)(3 1 4 7)两部分,这样第一台服务器所花时间就是5分钟,而第二台机器需要花15分钟,当然,所有任务完成的时间是按最迟完成的那台服务器的时间,即这样划分的话完成所有任务所需要的时间就是15分钟。而另外一种划分方法是(5 3 1)(4 7),这种划分方案完成所有任务的时间就是11分钟,也是最优的一种划分方案。
现在你的任务就是根据给定的N,K和每个任务要花费的时间,找出使完成所有任务时间最短的方案。
输入:
多组输入。
第一行输入N和K(1<=K<=N<=10000)。
第二行输入N个不大于1000的正整数,表示各个任要花费的时间。
N=K=0表示输入结束。
输出:
每行输出一个整数,对应对于每个数据(除了N=K=0不用输出)。
样例输入:
5 1
5 3 1 4 7
5 2
5 3 1 4 7
5 3
5 3 1 4 7
10 3
1 2 3 4 5 6 7 8 9 10
0 0
样例输出:
20
11
8
21
分析:
运用二分法寻找所需求的时间
设N个任务存放在task数组里。因为所求的时间点一定在max(task[1],task[N]) 与 sum(task[1]...task[N])之间,所以可在这个范围内不断二分,从而寻找所需的时间点
源代码:
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
int main()
{
int N,K,i=1,sum=0,mid=0;
while(cin>>N>>K &&N!=0 &&K!=0){
int task[1000];
for( i=1; i<=N; i++){
cin>>task[i];
sum+=task[i];
}
cout<<"总和是:"<<sum<<endl;
int left =max(task[1],task[N]);
cout<<"左边是:"<<left<<endl;
int right=sum;
cout<<"右边是:"<<right<<endl;
while(left<=right)
{
mid=(left+right)/2;
int result=0;
int j=1;
for(int i=1;i<=N;i++)
{
result+=task[i];
if(result>mid&&j<=K-1) {
result=0;j++;i--;
}
}
if(result>mid)
left=mid+1;
else
right=mid-1;
}
cout<<"最后的结果是:"<<left<<endl;
}
return 0;
}
运行结果测试为:
5 2
5 3 1 4 7
总和是:20
左边是:7
右边是:20
最后的结果是:11
5 3
5 3 1 4 7
总和是:40
左边是:7
右边是:40
最后的结果是:8
5 2
1 2 3 4 5
总和是:55
左边是:5
右边是:55
最后的结果是:9
5 3
1 2 3 4 5
总和是:70
左边是:5
右边是:70
最后的结果是:6
10 3
1 2 3 4 5 6 7 8 9 10
总和是:125
左边是:10
右边是:125
最后的结果是:21
5 1
1 2 3 4 5
总和是:140
左边是:5
右边是:140
最后的结果是:15
0 0
题目二:
水果忍者
题目描述
你知道水果忍者吗?这是一个智能手机上面很流行的游戏。
这个出色的游戏迎合了人类最喜爱的运动轨迹:抛物线。就是各种各样物体被扔出去之后都会形成的曲线运动。现在这里的问题也是关于抛物线的。
现在有N个水果,假设它们就是一个个在平面上的的圆,有着同样的半径。每个水果有着各自的位置和移动速度。由于重力的影响(这里假设重力常数g=10),所有水果都从一开始就沿着抛物线运动。你的目标就是在给定的时间限制之内,一次切到最多的水果,即是找到在某一时刻的一条直线穿过最多的圆。
输入格式
输入包含多给测试数据。
输入的第一行给出了测试数据个数T。
每个测试数据首先给出三个整数,水果数目N(<=100),水果的半径R(<=1000),还有时间限制E(<=1000)。
接下来有N行,每行给出4个实数,分别对应圆心坐标(xi, yi)和速度(vxi,vyi)。
所有数都是采用标准单位,所以你可以放心使用以下著名的物理公式来计算某一时刻水果所处的位置:
x' = x + vx * t
y' = y + vy * t - 0.5 * 10 * t * t
数据保证所有的浮点数的绝对值小于100000。
输出格式
对应每个测试数据,输出一个整数,即在时限内可以同时切到的水果数目的最大值。
样例输入
2
4 1 2
2.0 4.0 1.0 0.0
5.0 4.0 2.0 0.0
2.0 12.0 1.5 -4.0
-2.0 -5.0 10.0 10.0
4 1 1
2.0 4.0 1.0 0.0
5.0 4.0 2.0 0.0
2.0 12.0 1.5 -4.0
-2.0 -5.0 10.0 10.0
样例输出
4
3
提示
请注意一条直线“穿过”一个圆意味着,圆心与直线的距离小于圆的半径加上精度误差(1e-5)。
附:
平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。
先把N个点按x排序。
斜率k最大值为max(斜率(point[i],point[i+1])) 0 <=i <n-2。
复杂度Nlog(N)。
以3个点为例,按照x排序后为ABC,假如3点共线,则斜率一样,假如不共线,则可以证明AB或BC中,
一定有一个点的斜率大于AC,一个点的斜率小于AC。
源程序(不出结果):
#include <iostream>
#include <algorithm>
#include <math.h>
//#include <algorithm>
#include <stdlib.h>
#include <string.h>
using namespace std;
struct Circle{
float Xi,Yi;
float Vxi,Vyi;
int n;
};
Circle circle[101];
float abs(float a) // 求绝对值
{
return (a>0)?a:(-a);
}
float dis(float x, float y) //为计算距离
{
return sqrt(x*x+y*y);
}
void Xsort(Circle circle[],int N) //对结构体点的X坐标进行排序
{
int i,j=0;
for(i=0; i<N; i++)
{
for(j=i+1; j<N; j++)
{
if(circle[j].Xi<circle[i].Xi)
{
Circle tempx;
// int tempn;
tempx=circle[j];
circle[j]=circle[i];
circle[i]=tempx;
// tempn=circle[j].n;circle[j].n=circle[i].n;circle[i].n=tempn;
}
}
}
}
void Ysort(Circle circle[],int N) //对结构体点的X坐标进行排序
{
int i,j=0;
for(i=0; i<N; i++)
{
for(j=i+1; j<N; j++)
{
if(circle[j].Yi<circle[i].Yi)
{
Circle tempx;
// int tempn;
tempx=circle[j];
circle[j]=circle[i];
circle[i]=tempx;
// tempn=circle[j].n;circle[j].n=circle[i].n;circle[i].n=tempn;
}
}
}
}
float kmin(Circle circle[],int N) //找出点群中斜率最小的值 (对的)
{
float k[101],kmin;
for(int i=0; i<N-2; i++)
{
kmin=0.0;
k[i]=(circle[i].Yi-circle[i+1].Yi)/(circle[i].Xi-circle[i+1].Xi);
if(k[i]<kmin) kmin=k[i];
k[i]=(circle[i].Yi-circle[i+2].Yi)/(circle[i].Xi-circle[i+2].Xi);
if(k[i]<kmin) kmin=k[i];
k[i]=(circle[i+1].Yi-circle[i+2].Yi)/(circle[i+1].Xi-circle[i+2].Xi);
if(k[i]<kmin) kmin=k[i];
}
return kmin;
}
float kmax(Circle circle[],int N) //找出点群中斜率最大的值
{
float k[101],kmax;
for(int i=0; i<N-1; i++)
{
k[i]=(circle[i].Yi-circle[i+1].Yi)/(circle[i].Xi-circle[i+1].Xi);
kmax=k[0];
if(k[i]>kmax) kmax=k[i];
}
return kmax;
}
int main()
{
int T;
cin>>T;
while(T>=1)
{
int N,R,E,i,num=0;
//memset(m,0,sizeof(m));
cin>>N>>R>>E;
for(i=0; i<N; i++)
cin>>circle[i].Xi>>circle[i].Yi>>circle[i].Vxi>>circle[i].Vyi;
Xsort(circle, N);
for(i=0; i<N; i++)
cout<<circle[i].Xi<<" "<<circle[i].Yi<<endl;
float mink=kmin(circle,N);
float maxk=kmax(circle,N);
cout<<"斜率最小值:"<<mink<<endl;
cout<<"斜率最大值:"<<maxk<<endl;
float a,b;
int t;
float d[101];
Ysort(circle,N);
//cout<<circle[0].Yi<<endl<<circle[N-1].Yi<<endl;//对的
int k=0,tempmax=0;
for(b=circle[0].Yi; b<=circle[N-1].Yi; b++){
for(a=mink; a<=maxk; a++){
for( t=0; t<=E; t++){
num[t]=0;
for(i=0; i<N; i++)
{
circle[i].Yi += t*circle[i].Vyi-5*circle[i].Vyi*circle[i].Vyi;
circle[i].Xi += t*circle[i].Vxi;
d[i]=abs(circle[i].Yi-a*circle[i].Xi-b)/dis(1.0,a);
if(d[i]<=R) num[t]++; //t时刻某直线的可切水果数
}
//cout<<num[t]<<endl;
if(num[t]>maxnum) maxnum=num[t];
if(maxnum>tempmax) tempmax=maxnum;
}
tempmax=maxnum;
}
}
// int n=0,f[99999];
// for (i = 0; i < k; i++)
// for (int j = 0; j < t; j++)
// f[n++] = num[i][j];
//
// sort(f,f+n);
cout<<"结果是:"<<f[n-2]<<endl;
//cout<<maxnum<<endl;
T--;
}
return 0;
}