百度之星 负载均衡 几种解法

//2013-3-26 Charlie
//百度之星题目——“负载均衡”


/*平衡负载
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*/

解法一:

#include <cstdlib>
#include <iostream>
using namespace std;

#define INFINITY 100000000

int time = INFINITY;
int count = 0;
int *a,*s;
int n,k;

//递归分配函数;
void allot(int n, int k);
//将数组a[]中,从count位置开始的前i个值的和存储到s[_k-1];
void save2s(int _k, int i, int count);
//求数组s[]中k个数的最大值;
int max_s();

int main(){
	
	cin>>n>>k;
	while(!(n==0&&k==0)){
		a = (int*)malloc(n*sizeof(int));
		s = (int*)malloc(k*sizeof(int));

		for(int i=1;i<=n;i++)
			cin>>a[i-1];

		allot(n,k);
		cout<<time<<endl;

		free(a);
		free(s);
		time=INFINITY;
		count=0;

		cin>>n>>k;
	}
	return 0;
}

void allot(int n, int k){
	//递归分配函数
	if (k==1){
		save2s(k,n,count);
		
		int maxs = max_s();
		if (maxs < time){
			time = maxs;
		}
		return;
	}

	for(int i=1; i<=n-(k-1);i++){
		save2s(k,i,count);
		count+=i;
		allot(n-i,k-1);
		count-=i;
	}
}

void save2s(int k, int i, int count){
	int sum = 0;
	for(int j = count;j<count+i;j++){
		sum += a[j];
	}
	s[k-1] = sum;
}

int max_s(){
	int max = 0;
	for(int j=0;j<k;j++){
		if (s[j]>max)
		{
			max = s[j];
		}
	}
	return max;
}

解法一的另一种写法:

#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

int n,k;
int *a,*divide;//a为输入数组,divide中每一个数代表一个机器所做任务的个数
int count;//组号0~k-1
// int time;//最终结果


void fun(int n,int k);
int result();
void print();

int main(){

    ifstream cin("../input.txt");
    if(cin.fail())cout<<"Input file error!"<<endl;
    cin>>n>>k;
    while(n!=0 && k!=0){

        count=-1;
        time=10000;

        a=(int*)malloc(sizeof(int)*n);
        divide=(int*)malloc(sizeof(int)*k);
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        fun(n,k);
        cout<<time<<endl;
        cin>>n>>k;
    }
	return 0;
}

void fun(int n,int k){
	if(k==1 ){
		divide[++count]=n;
		int tmp=result();
		if(tmp<time){
			time=tmp;print();
		}
		count--;
		return;
	}
	for(int i=1;i<=n-(k-1);i++){
		divide[++count]=i;
		fun(n-i,k-1);
		count--;
	}
}

//得到一次划分的运行时间
int result(){
	int max=0;
	int start=0;
	int s;
	for(int i=0;i<k;i++){
		s=0;
		for(int j=start;j<start+divide[i];j++){
			s+=a[j];
		}
		if(s>max){
			max=s;
		}
		start+=divide[i];
	}
	return max;
}
void print(){
	for(int i=0;i<k;i++)
		cout<<divide[i]<<',';
	cout<<endl;
}



解法二:

//最优时间一定在均值和所有数和之间
#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;

int check(int x);

int n,k;
int *a;
int main(){
    int sum;
    int avg;
    int maximum;
    ifstream cin("../input.txt");
    if(cin.fail())cout<<"Input file error!"<<endl;
    cin>>n>>k;
    while(n!=0 && k!=0){
        sum=0;
        maximum=10000;
        a=(int*)malloc(sizeof(int)*n);
        for(int i=0;i<n;i++){
            cin>>a[i];
            sum+=a[i];
        }


        avg=sum/k;//最后结果值必定在avg到sum之间
        int s=0;
        for(int i=avg;i<=sum;i++){
            s=check(i);
            if(s!=0 && s<maximum){
                maximum=s;
            }
        }
        cout<<maximum<<endl;
        cin>>n>>k;
    }
}

int check(int x){
    bool flag=false;
    int temp_max=0;
    int temp=0;
    int number=0;

    for(int i=0;i<n;i++){
        if(temp+a[i]<=x){
            temp+=a[i];
            if(temp==x)
                flag=true;
            if(i==n-1 && number==0)
                temp_max=temp;
        }else{
            if(temp>temp_max){
                temp_max=temp;
            }
            temp=0;
            number++;
            if(number>k){
                flag=false;
                break;
            }
        }
    }
    if(!flag)
        return 0;
    else
        return temp_max;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值