由于牛的产奶周期最大为10,1.2.3.....10的最小公倍数是MT = 2520,所以把MT作为最大的周期,然后枚举这个周期内的每一天,看产奶量最小的牛是否唯一,然后杀掉是唯一的最少产奶的那头牛,知道遇到一个周期内没有牛被杀掉。这样就到达了一个稳定的最终状态,统计剩下的牛,和杀掉最后一头牛用去的时间。注意一头牛都不杀的情况应该输出天数为0.
#include <stdio.h>
#include <string.h>
const int N = 1005;
const int M = 15;
const int INF = 1 << 30;
const int tmp = 2520;
int n, s[N], g[N][M], vis[N];
void init()
{
scanf("%d\n", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &s[i]);
for (int j = 0; j < s[i]; j++)
scanf("%d", &g[i][j]);
}
}
bool find(int d, int& id)
{
int Min = INF;
bool flag = false;
for (int i = 0; i < n; i++)
{
if (vis[i]) continue;
int c = d % s[i];
if (Min > g[i][c])
{
id = i;
Min = g[i][c];
flag = true;
}
else if (Min == g[i][c])
flag = false;
}
return flag;
}
void solve()
{
int id, del = -1, cnt = 0;
memset(vis, 0, sizeof(vis));
for (int i = 0; i - del <= tmp; i++)
{
if (find(i, id))
{
del = i;
vis[id] = 1;
cnt++;
}
}
printf("%d %d\n", n - cnt, del + 1);
}
int main ()
{
int cas;
scanf("%d", &cas);
while (cas--)
{
init();
solve();
}
return 0;
}
每次根据剩下的牛的周期计算最大周期
#include <cstdio>
#include <cstring>
#define N 1010
#define M 15
bool killed[N];
int c[N];
int a[N][M];
int n;
int kill(int day) //在day这天杀牛
{
int min=260,cc=0,k,val; //牛的最高产奶量为250
for(int i=1; i<=n; i++) if(!killed[i])
{
val=a[i][ day%c[i] ];
if(val==min) cc++;
else if(val<min)
{ min=val,k=i; cc=1;}
}
if(cc==1) return k;
else return 0;
}
int gcd(int x , int y) //得到两个数的最大公约数
{
return y==0 ? x : gcd(y,x%y);
}
int lcm(int x ,int y) //得到两个数x,y的最小公倍数
{
int tmp;
if(x<y) { tmp=x; x=y; y=tmp; }
int m=gcd(x,y); //先得到两个数的最大公约数
return x/m*y;
}
int get_lcm()
{
int m=1; //保存最后的最小公倍数
for(int i=1; i<=n; i++) if(!killed[i])
m=lcm(m,c[i]);
//用当前这只牛的周期和之前已经算出来的最小公倍数在算一次最小公倍数
return m;
}
int main()
{
int T,start,end,ccount,lastday;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
scanf("%d",&c[i]);
for(int j=1; j<c[i]; j++)
scanf("%d",&a[i][j]);
scanf("%d",&a[i][0]);
}
memset(killed,0,sizeof(killed));
ccount=0; start=1; lastday=0;
while(1)
{
int OK=0;
int L=get_lcm();//在剩余的牛中计算最小公倍数
end=start+L-1;
for(int i=start; i<=end; i++) //枚举整个周期
{
int k=kill(i); //杀牛,不能杀牛返回0,能杀牛则返回牛的编号
if(k)
{
killed[k]=1; //标记
ccount++; //计数
lastday=i; //更新最后一天
OK=1; //标记有杀牛
}
}
start=end+1; //准备下一个周期
if(!OK || ccount>=n) //在这一个周期没有杀牛或者牛全部杀光了
break;
}
printf("%d %d\n",n-ccount,lastday);
}
return 0;
}