WUSTOJ 1276: 峰峰不搞G(Java)

版权声明:转载请注明出处 https://blog.csdn.net/pfdvnah/article/details/89429818

1276: 峰峰不搞G

题目

  给 n 数量的油漆,写出最大的数,每个数对应有油漆的花费。更多内容点击标题。

分析

  我读完题,就想到用动态规划,结果是Time Limit Exceed。然后看了看提交,别人的代码都很短,我就想到应该是有规律的。
  这道题目的问题是计算出最大的数,我们就要考虑什么样的数最大,显然位数越多,数肯定越大。在Simple Input中的第一组数据中,你肯定愿意写5个5(55555),而不是2个6(66),就是这个道理。
  那如果是下面这组数据呢?你该怎么办?

36
11  12  13  45  78  46  51  45  84

  你会发现,可以写3个1(111),或者3个2(222),但是正确结果应该是 321 。因此,我的方法是先用油漆写出最长位数并且花费油漆最少的数,即 111,然后再用多出来的 3 个油漆检查是不是能够增加数。从前往后检查 111 , 从9-1判断。步骤如下:

数:111		剩余油漆:3
841173,剩余的油漆不够写数字9
451134,剩余的油漆不够写数字8
......
13112,因此可以将第一个数字1变成3,数:311		剩余油漆:1
841173,剩余的油漆不够写数字9
......
13113,剩余的油漆不够写数字3
12111,因此可一将第二个数字变成2,数:321		剩余油漆0
第三轮,剩余的油漆不能写任何比1大的数,因此最终结果为321

  上述大意就是,先用一定油漆写出位数最长并且使用油漆最少的数,再将多余的油漆检查是否能将数中的最高位的数字替换成更大的数字。直到最后一位数字或者无较大可替换的数字为止。
  这里提供几组测试数据,毕竟题目给的三组数据有点少,仅供参考。

36
11  12  13  45  78  46  51  45  84
1
1   1   1   1   1   1   1   1   1
2
1   1   1   1   1   1   1   1   1
17
50  40  80  61  7  19   54  48  8
17
50  40  80  61  7   19  54  9   8

  正确结果是:

321
9
99
99
99

  直接看代码吧,调试更容易看懂。

代码

/**
 * time 252ms
 * @author PengHao
 * @version A3.1
 * @date 2019-04-21 上午9:44:18
 */

import java.util.Scanner;

public class Main {

	private Scanner sc;
	private int n; // 买的油漆数量
	private int[] tab; // 每个数字对应的油漆数量
	private String maxNum; // 能写出的最大的数值
	private int maxLen; // 能写出的数值的最大长度
	private int maxIndex; // 写出最长数值且用料最少的数字的下标

	public Main() {
		sc = new Scanner(System.in);
		tab = new int[10]; // 下标从1开始
		while (sc.hasNext()) {
			input();
			findMaxLen();
			if (0 == maxLen) { // 一个数字都不能写
				System.out.println("Lihun!");
				continue; // 下一组数据
			}
			initMaxNum();
			increase();
			System.out.println(maxNum); // 输出
		}
		sc.close();
	}

	/**
	 * Input data
	 */
	private void input() {
		n = sc.nextInt();
		for (int i = 1; i <= 9; i++) {
			tab[i] = sc.nextInt();
		}
	}

	/**
	 * Set the <b>maxLen</b> and <b>maxIndex</b>
	 */
	private void findMaxLen() {
		maxLen = maxIndex = 0;
		for (int i = 9; i > 0; i--) {
			if (n / tab[i] > maxLen) { // 第i个数字能写出的位数比maxLen还多
				maxIndex = i;
				maxLen = n / tab[maxIndex];
			} else if (n / tab[i] == maxLen) { // 写出的位数相同
				if (tab[i] < tab[maxIndex]) { // 看哪个数字用的油漆少
					maxIndex = i; // 写用的油漆少的那个数字
				}
			}
		}
	}

	/**
	 * Initialize <b>maxNum</b>
	 */
	private void initMaxNum() {
		maxNum = "";
		// 将最大长度得到的数值赋给结果
		for (int i = 0; i < maxLen; i++) {
			maxNum += maxIndex;
		}
	}

	/**
	 * Substituting some Numbers makes the result bigger
	 */
	private void increase() {
		int left = n % tab[maxIndex]; // 写出了maxNum后剩下的油漆
		int j;
		String small, big;
		// 已经写出的数值的每一位检查一遍,看能不能替换成更大的数字
		for (int i = 0; i < maxLen; i++) {
			j = 9; // 从9开始
			// 因为可能有两个数字需要同样多的油漆,因此left可以等于0
			// 如果数字j比已经写出的数字还小就不用替换了,那样只会使得结果更小
			while (left >= 0 && j > maxIndex) {
				if (left >= tab[j] - tab[maxIndex]) { // 剩余的油漆可以使得写出的数字更大
					small = String.valueOf(maxIndex);
					big = String.valueOf(j);
					maxNum = maxNum.replaceFirst(small, big);
					left -= tab[j] - tab[maxIndex]; // 剩余油漆变少
					break; // 第i个数字已经替换,直接退出找下一位
				}
				j--; // 先写较大的数字,因此这里是减
			}
		}
	}

	public static void main(String[] args) {
		new Main();
	}

}

写在最后:

  1. 如需转载,请于标题下注明链接形式的wowpH的博客即可;
  2. 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
  3. 如果有疑问欢迎评论留言,尽力解答。

猜你喜欢

转载自blog.csdn.net/pfdvnah/article/details/89429818