HDU4671 备份计划
现在有n个服务器和m个数据库,每个数据库都有一个单子,单子上写的是这n个服务器的一个排列组合,当有人要使用某个数据库时,优先调用这个数据库单子上的第一个服务器来使用,如果这个服务器坏了,就调用第二个,依次类推。这m个数据库的单子要求,n个服务器(可以允许一个服务器坏了,对坏了的服务器不作要求)都负载均衡。当某人通过一个数据库调用了一个服务器时,那么这个服务器就有了一个负载Ai。负载均衡要求:对于任意两个没坏的服务器有
|Ai-AJ|<=1。
输入:包含多个实例,每个位一行N与M(2<=N<=100,1<=M<=100)
以EOF表示输入实例的结束。
输出:对应输出每个实例的M个排列组合。每行一个。
分析:朴素的做法是,依次生成要求的M个排列组合,然后分别判断所有服务器都OK,和某一台服务器坏了(共n中情况),这些情况下,所生成的M个排列组合对应的各服务器负载数据是都满足均衡要求。但是明显生成排列组合时间复杂度太高。
现在对题目的数据进行分析:
1) 若N==M则:要满足所有服务器都OK时要求M个数据库的单子中第一个服务器正好包括了N个服务器(每个一次),不能有哪个服务器多或少一次。且此时也满足任一服务器坏了的条件。
如N=5,M=5时为:
1…
2…
3…
4…
5…
2) 若N>M则:所有服务器OK时,要求M个数据库的单子中第一个服务器正好包括了M个不同的服务器(每个一次)。M个单子的第二列只能包括剩下的N-M个服务器中的任意一个或几个。依然满足任一服务器坏了的情况。
N=8且M=5时;
1 6 …
2 7…
3 8…
4 6…
5 6…
3) 若N<M时则:M个排列的第一列要求N各数循环填写就行,这样的结果就是N个服务器中,集合S1中的服务器在M个排列中出现了(M)/N次,集合S2中的服务器在M个排列中出现了(M-1)/N+1次。服务器全OK时不用考虑第二列,但是现在考虑这种情况:
假设N这个数出现了8次,1到N-1这些数都出现了9次。或者i到N这些数出现了8次,1到i-1这些数出现了9次。当N这个服务器坏了,将有8个新服务器出现,替代N,那么如何保持服务器的负载均衡呢?
正确的做法是:对于第一列,从1到N循环放就行,对于第一列,其中每个i在第n*k+i行(0<=k,且n*k+i<=M),所有第一列为i的行应该从N,N-1,一直放到1(遇到i直接跳过就行)。第一列为i+1的行也应该这么放。I从1循环到N即可。
N=3,M=14时:
1 3 2
2 3 1
3 2 1
1 2 3
2 1 3
3 1 2
1 3 2
2 3 1
3 2 1
1 2 3
2 1 3
3 1 2
1 3 2
2 3 1
#include<cstdio>
#include<cstring>
using namespace std;
int p[200][200];
int use[200];
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
if(n==m)
{
for(int i=1;i<=m;i++)
p[i][1]=i;
for(int i=1;i<=m;i++)
{
memset(use,0,sizeof(use));
use[p[i][1]]=1;
for(int j=2;j<=n;j++)
{
for(int k=1;k<=n;k++)if(use[k]==0)
{
use[k]=1;
p[i][j]=k;
break;
}
}
}
}
else if(n>m)
{
for(int i=1;i<=m;i++)
p[i][1]=i;
for(int i=1;i<=m;i++)
p[i][2]=n;
for(int i=1;i<=m;i++)
{
memset(use,0,sizeof(use));
use[p[i][1]]=use[p[i][2]]=1;
for(int j=3;j<=n;j++)
{
for(int k=1;k<=n;k++)if(use[k]==0)
{
use[k]=1;
p[i][j]=k;
break;
}
}
}
}
else if(n<m)
{
for(int i=1;i<=m;i++)
p[i][1]=(i-1)%n+1;//赋值第一列,并记录次数
for(int i=1;i<=n;i++)
{
int start=n;
if(i==n)start--;
for(int k=0;k*n+i<=m;k++)
{
p[k*n+i][2]=start--;
if(start==0)start=n;
if(start==i)start--;
if(start==0)start=n;
}
}
for(int i=1;i<=m;i++)
{
memset(use,0,sizeof(use));
use[p[i][1]]=use[p[i][2]]=1;
for(int j=3;j<=n;j++)
{
for(int k=1;k<=n;k++)if(use[k]==0)
{
use[k]=1;
p[i][j]=k;
break;
}
}
}
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",p[i][j]);
printf("\n");
}
}
return 0;
}