暴力uva10273

由于牛的产奶周期最大为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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值