非穷举方法解决poj 1006

/**Author:Founder Watts
 *作者原创,转载请注明出处
 */

非穷举方法解决poj 1006
主要思想,将问题维度不断降低,从原本的三维降到一维
设三项数据分别为a,b,c,最后天数为d
(数据修正:以b为中心,使a和c向b靠拢,并使a <= b <= c )
其中b是本问题的核心,首先进行第一次降维,以b的高峰期为基准,计算b-a和c-b他们高峰期的差值,下面为作者统计的数据:
设n为三个高峰第一次相同起,b的第n个高峰,n>=0
b-a = 5 * n (0 <= n <= 4)
= 2 + 5 * (n - 5) (5 <= n <= 9)
= 4 + 5 * (n - 10) (10 <= n <= 13)
= 1 + 5 * (n - 14) (14 <= n <= 18)
= 3 + 5 * (n - 19) (19 <= n <= 22)

c-b = 5 * n(0 <= n <= 6)
= 2 + 5 * (n - 7) (7 <= n <= 13)
= 4 + 5 * (n - 14) (14 <= n <= 19)
= 1 + 5 * (n - 20) (20 <= n <= 26)
= 3 + 5 * (n - 27) (27 <= n <= 32)

有了上面的公式,我们就能以a与b之间的差和b与c之间的差完成第一次降维,下面开始第二次降维
假设通过代入数据求出 b-a 的高峰数n为p, c-b 的高峰数n为q,此时以b-a为基准进行降维
(数据修正:使q >= p,若 q < p,使 q = q + 33,p 不要变)
设m为b-a进行的轮数,通过公式 (m - 1) * 23 % 33 = (q - p)求出第m轮时,b-a中的n=0对应c-b中的n为多少,下面是作者算出的对照关系:
1:0 2:23 3:13 4:3 5:26 6:16 7:6 8:29 9:19 10:9 11:32 12:22 13:12 14:2 15:25 16:15 17:5 18:28 19:18
20:8 21:31 22:21 23:11 24:1 25:24 26:14 27:4 28:27 29:17 30:7 31:30 32:20 33:10
根据 q - p 的值在上表中选出m(注意p-q <0或>32的情况)
有了关键数据m,我们就可以开始计算出下一次重合的天数
(输入数据中给出的b的天数) - ((m - 1) * 23 + p) * 28 + 21252 - (输入数据中给出的d的天数)
其中,21252为三个高峰重合的周期,有23*28*33求得(注意结果为 <=0或 >21252的情况要修正)。

以下是Java代码:

/**Author:Founder Watts
 *作者原创,转载请注明出处
 */

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        int a,b,c,d;
        ArrayList<Integer> answer = new ArrayList();
        while((a = input.nextInt())!=-1){
            b = input.nextInt();
            c = input.nextInt();
            d = input.nextInt();
            answer.add(caculate(a,b,c,d));
        }
        for(int i = 0 ; i < answer.size(); ++i){
            System.out.println("Case " + (i + 1) +": the next triple peak occurs in " + answer.get(i) + " days.");
        }

    }
    public static int caculate(int a,int b,int c,int d){
        int[] mData = new int[]{1,24,14,4,27,17,7,30,20,10,33,23,13,3,26,16,6,29,19,9,32,22,12,2,25,15,5,28,18,8,31,21,11};
        if(a > b)
            a -= ((a - b) / 23 + 1) * 23;
        if(b > c) c += ((b - c) / 33 + 1) * 33;
        int p = getPFromAandB(a,b);
        int q = getQFromBandC(b,c);
        if(q < p) q += ((p - q) / 33 + 1) * 33;
        int m = mData[(q - p) % 33];
        int answer = b - ((m - 1) * 23 + p) * 28 + 21252 - d;
        if(answer <= 0) answer += ((0 - answer) / 21252  + 1) * 21252;
        if(answer > 21252) answer %= 21252;

        return answer;
    }

    public static int getPFromAandB(int a,int b){
        int answer = -1;
        int cha = b - a;
        switch(cha%5){
        case 0:
            answer =  cha / 5;
            break;
        case 1:
            answer = (cha - 1) / 5 + 14;
            break;
        case 2:
            answer = (cha - 2) / 5 + 5;
            break;
        case 3:
            answer = (cha - 3) / 5 + 19;
            break;
        case 4:
            answer = (cha - 4) / 5 + 10;
            break;

        }
        return answer;
    }
    public static int getQFromBandC(int b,int c){
        int answer = -1;
        int cha = c - b;
        switch(cha%5){
        case 0:
            answer =  cha / 5;
            break;
        case 1:
            answer = (cha - 1) / 5 + 20;
            break;
        case 2:
            answer = (cha - 2) / 5 + 7;
            break;
        case 3:
            answer = (cha - 3) / 5 + 27;
            break;
        case 4:
            answer = (cha - 4) / 5 + 14;
            break;

        }
        return answer;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值