HDU4671

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次,1N-1这些数都出现了9次。或者iN这些数出现了8次,1i-1这些数出现了9次。当N这个服务器坏了,将有8个新服务器出现,替代N,那么如何保持服务器的负载均衡呢?

正确的做法是:对于第一列,从1N循环放就行,对于第一列,其中每个i在第n*k+i行(0<=k,且n*k+i<=M),所有第一列为i的行应该从NN-1,一直放到1(遇到i直接跳过就行)。第一列为i+1的行也应该这么放。I1循环到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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值