TOJ 3817 Matchsticks
原题链接:http://acm.tju.edu.cn/toj/showp3817.html
第一次上toj做题,今天开始感觉这个题想仔细点应该是不难的。但是写好了以后上去直接攒了七八个wa,怎么想也想不出哪儿错了。直接搜解题报告也没有。因为是今天新出的题吧。晚上几乎使上了各种手段包括各种外援后终于知道哪儿错了。费劲九牛二虎之力改完后ac,真的是折磨人啊。这种BT模拟题是最要命的。
下面讲一下这个题的解法,给一些棍子,摆出最大数和最小数。很容易想到最大就是位数尽量多的情况下,每位的数值尽量大。最小就是相反。求最大数很好求,因为只要摆尽量多的1,如果不是偶数,就摆一个7,再加余下的1。把最小数就比较麻烦。首先确定最多有多少位,如果是7的倍数则有n/7位,每位是8。如果n小于7,则直接输出一位数,就是最小的。这两种是简单的情况。
一般的情况是把一堆棍子分成两堆,一堆是7的倍数,一堆是除以7的余数。两步处理:
(1)如果余数为1,则把1和一个8换成2根和6根,不然就直接把第一位置成需要棍数k的那个最小的数。
(2)从前往后变换,如果和8相邻的那一位能和8一起换位两位两位更小的数则变换,直到没有8或者不能变换为止。
#include<iostream> using namespace std; //最小的数位数尽可能少的情况下,数值尽量小 //最大数位数尽可能多的情况下,数字尽量大 int main() { int n[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6}; int tot, x, d, k, flag, t, i; scanf("%d", &tot); while (tot--) { scanf("%d", &x); if (x <= 7)//小于等于7时最小的就是一位数 { for (int i = 1; i < 10; i++) if (x == n[i]) { printf("%d ", i); break; } } else { //想法就是先转换成位数最少的数 //然后从前往后把相邻的两位替换成棍数一样数值却小的两位数 k = x / 7; d = x % 7; if (d) { int tem; if (d == 1)tem = 9; else for (int i = 1; i < 10; i++) if (d == n[i]) { tem = i; break; } bool r = true;//如果是第一位,不能为0 while (k) { bool flag = true; if (r) i = 1; else i = 0; r = false; for (i; i <= tem; i++) { for (int j = 0; j < 8; j++) if (n[i] + n[j] == d + n[8]) { printf("%d", i); tem = j; flag = false; k--; break; } if (!flag)break; } if (flag)//如果没有找到,直接退出 { printf("%d", tem); break; } d = n[tem];//没有退出则继续 if (!k)//如果已经到了最后一位则不再循环 { printf("%d", tem); break; } } } for (int i = 0; i < k; i++) printf("8"); printf(" "); } //打印最大位比较简单 k = x / 2; t = x % 2; if (t) { printf("7"); k--; } for (int i = 0; i < k; i++) printf("1"); printf("\n"); } return 0; }