Source: 2013 Multi-University Training Contest 7 1006
题目大意: 题目意思还是比较麻烦的,当时做多校的时候询问题意的人就特别多。给你n个服务器,m个数据库。每个数据库有一个序列,每个序列有n个数,作为优先请求的顺寻,例如n=5,m=3.对于 第一个数据库假设排列是 1 2 3 4 5那么如果1号服务器没坏,这个数据库就向一号服务器递交申请使用,这时候2号是空闲的。如果一坏了,那么将使用二号,以此类推。那么m个数据库就会有m个n个数的排列。但是这样的排列必须满足一定得条件,就是对于一个时刻,最多被使用服务器的次数减去最少被使用的服务器次数不能超过1(<=1)。这就是说平衡每个服务器的使用,尽可能使得工作平均。同时如果假定一个服务器坏掉(最多一个),这是的工作状态也是满足这个平衡条件的(坏掉的不计入使用次数)。输出这样的排列,Special Judge,输出一种可能即可。
给的样例 n=5 m=3
2 4 3 1 5 如果都没坏, 1,2,3使用1次,4,5使用0,最大不超过1. 如果4,5坏掉,对使用暂时没用影响。如果1坏了,那么2,5,3被使用……2,3坏掉一样 1 5 4 2 3 3 5 2 4 1
思路:因为要尽可能使每种服务器使用均衡,对于第一次序的,只需要按照1,2,3……n,1,2,3……这样排列就好了。
例如 n=6 m=3 为 n=3 m=6 为
1 1
2 2
3 3
1
2
3
因为最多坏掉一个,其实只是将第二列左移到坏掉的一列上,其实只需要考虑前两列。因为我们的排序时尽可能使小的号码使用先,所以号码大的必然比小的使用次数少。那么我们对于替换就优先使用大序号替换。 我们再开一个数组t,记录当前替换序号,初始化为n,我们只需要讨论一号工作站相同的情况的第二列,设为a。 如果第二列与第一列不同 t[a]加入第二列,t[a]--;如果与第一列相同,t[a]-1加入再--。之后两列拍好,后面n-2列只要不重复即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int s[102];
int a[102][3];
int main()
{
int n,m; //n为sever m 为database
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(s,0,sizeof(s));
memset(a,0,sizeof(a));
int temp=0;
for(int i=1; i<=m; i++)
{
a[i][1]=(temp)%n+1;
temp=(temp)%n+1;
}
temp=n;
for(int i=1; i<=n; i++)
s[i]=n;
for(int i=1; i<=m; i++)
{
int t=a[i][1];
if(a[i][1]!=s[t])
{
a[i][2]=(s[t]);
s[t]=(s[t]-2+n)%n+1;
}
else
{
a[i][2]=(s[t]-2+n)%n+1;
s[t]=(s[t]-2+n)%n+1;
s[t]=(s[t]-2+n)%n+1;
}
}
int temp1=1;
for(int i=1; i<=m; i++)
{
temp1=1;
for(int j=1; j<=n; j++)
{
if(j==1||j==2) cout<<a[i][j]<<" ";
else
{
while(temp1==a[i][1]||temp1==a[i][2])
temp1++;
cout<<temp1;
if(j!=n)cout<<" ";
temp1++;
}
}
cout<<endl;
}
}
}