题意:(已经过本人转化。。。)有M个数据站,N个服务器,每个数据站有一个序列,这个序列就是该数据站存放自己的数据备份时的优先级顺序,如果排在第一的服务器坏了,就往排第二的服务器里存放自己的备份,以此类推直到可以存放自己的备份为止。这么一来,每个服务器就会存放一定数量的数据站的数据备份。
例如,所有服务器都没坏,而A数据站和B数据站拥有的服务器优先级序列中第一个都是服务器2,那么第二个服务器就存放了两个备份了,因为存放了A数据站的和B数据站的数据。
现在记录每个服务器所存放的备份数量为A[i],要求任意i,和j满足|A[i]-A[j]|<=1。
但是,每个服务器都会有坏掉的可能,要求任意坏掉恰好一个服务器的时候都有任意i,和j满足|A[i]-A[j]|<=1。要你输出所有数据站的优先级序列,使得上述条件成立。
思路:在服务器都没坏的时候,注意到服务器每排在一个数据站的第一位时,这个服务器存放的备份就多一次,也就是说,一个服务器排在K个数据站的第一位的话,A[i]=K。题目可以转化成有M颗糖果,N个盒子,每个盒子装A[i]颗糖果。要求|A[i]-A[j]|<=1,这个很好办,只要糖果均匀分派就行了。
例如10个糖果,3个盒子,那么只要分配成4,3,3就可以了。
那么,如果一个服务器坏了,那么它排第一位的时候都变成了排在第二位的那个来代替。相当于把其中一盒糖果回收,把那个盒撤掉,再重新均匀分配回收的糖果。例如4,3,3,现在把第2盒糖果回收,重新分配,那么就会分配成5,5。
知道思路以后,只要均等分配排第一的次数,然后对于每个排第一的数字,又均匀分配剩下的数字就好了。确定了排头的两个,后面就可以任意排列了,因为每次只会坏掉一个服务器,所以只有前两个服务器有效。
#include<cstdio> #include<cstring> int N,M; int f2[105][2];//记录每个数据站的排头两个服务器 int A[105]; int main() { while(~scanf("%d %d",&N,&M)) { memset(A,0,sizeof(A)); memset(f2,0,sizeof(f2)); for(int i=1;i<=N;++i)//处理A[i] { A[i]=M/N;//体现均匀分配 if(M%N>=i) ++A[i];//将余下的再均匀分配 } int cnt=1; for(int i=1;i<=N;++i) for(int j=1,k=N;j<=A[i];++j,--k) { while(i==k || k==0) { if(i==k) --k; if(k==0) k=N; } f2[cnt][0]=i,f2[cnt][1]=k,++cnt;//分配每个数据站的排头两个服务器 } for(int i=1;i<=M;++i)//输出 { printf("%d %d",f2[i][0],f2[i][1]); for(int j=1;j<=N;++j) if(j!=f2[i][0] && j!=f2[i][1]) printf(" %d",j); printf("\n"); } } return 0; }