SCNU 2015ACM新生赛初赛【1007. ZLM的扑克牌】解题报告

 
      题目链接详见SCNU 2015新生网络赛 1007. ZLM的扑克牌 。
 
      其实我在想这题的时候,还想过要不要设置求最小的排列,并且对于回文数字的话,可以把扑克牌折起来(从而这个数字会变小);甚至要不要设置扑克牌旋转、翻转之后,读出的数字要改变。但这样的话好像我也不会做辣!= =|||于是这道题目最后就变成了一个简单贪心题。 题目大意大概就是这样的:给出一个包含$n$个数字的多重集,要求使用集合中的元素拼凑出一个最大的数字,问最大所能拼凑出的数字是多少?
 
      贪心算法需要对贪心策略进行证明。比如大部分同学可能会想到的是,做一个简单的排序,把数字大的排在前面,数字小的排在后面,然后按顺序输出就好啦!但很可惜这是错的!因为对于$12345$,它比$67$要大,但$67$应该排在它的前面,因为$1234567$是小于$6712345$的。
 
      我们考虑两个数字串$A$和$B$,组合得到一个新的数字串$AB$或$BA$,定义关系$\succ$,当且仅当$AB > BA$严格成立时,$A \succ B$成立。对于集合中另一个数字串$C$且$A \succ B$,如果$C \succ A$,则一定满足$C \succ B$;如果$B \succ C$,则一定满足$A \succ C$;否则应当再进行一次比较以确定$A$、$B$、$C$三者的序关系。对于全集$S_{N}$,至多进行有限次即$O(N^{2})$的比较可以使整个集合满足全序关系,于是基于这种比较的排序方法可行。
 
      接下来考虑下代码,因为输入输出量比较大,而时限只有1s,所以C++的输入输出方法被卡得死死的,只要使用了就一定会TLE。另外STL的string类也会导致TLE,这个我原先倒是没想过要卡的,但至少给大家一个警醒,不要滥用STL,STL大概为了做到泛型编程和通用性,通常会损失一些性能,因此在某些时候远不及于自己写的代码。
 1 #include 
 2 #include 
 3 #include 
 4 
 5 namespace cmp {
 6     char tx[15], ty[15];
 7     int compare(const void*a, const void*b) {
 8         strcat(strcpy(tx, (char*)a), (char*)b);
 9         strcat(strcpy(ty, (char*)b), (char*)a);
10         return strcmp(ty, tx);
11     }
12 }
13 
14 char x[10001][7];
15 int main() {
16     int cse, T, N, i;
17     scanf("%d", &T);
18     for(cse=1; cse<=T; cse++) {
19         printf("Case #%d:\n", cse);
20         scanf("%d", &N);
21         for(i=0; i)
22             scanf("%s", x[i]);
23         qsort(x, N, 7, cmp::compare);
24         for(i=0; i)
25             printf(x[i]);
26         puts("");
27     }
28     return 0;
29 }
 
      上面的代码用了C++的命名空间,你也可以选择用函数内静态变量,或直接暴露成全局变量。其中利弊请自行体会= =||
      另外 注意一下我在qsort的compare中写的是strcmp(ba,ab),其中原因请参看 strcmp函数返回值说明 以及 qsort函数参数说明 ,并注意一下$a$和$b$之间的关系。
 
      附:数据生成程序如下:
 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 
 6 int main() {
 7     freopen("in.txt", "w+", stdout);
 8     int T = 100;
 9     printf("%d\n", T);
10     srand(time(NULL));
11     for(int a=1; a<=4; a++)
12         for(int b=0; b10; b++) {
13             int N = rand()%((int)pow(10, a)-2)+2;
14             printf("%d\n", N);
15             for(int i=0; i) {
16                 int X = rand()%((int)pow(10, 6-a)-1)+1+(int)pow(rand()%10, 7-a);
17                 printf("%d ", X);
18             }
19             puts("");
20     }
21     return 0;
22 }
Click To View Code
 
——by BlackStorm, from here: http://www.cnblogs.com/BlackStorm/p/4988586.html .

你可能感兴趣的:(SCNU 2015ACM新生赛初赛【1007. ZLM的扑克牌】解题报告)