NWERC2016-Problem A(Arranging Hat)

Arranging Hat is a cushy job indeed; high impact work, absolute authority, and 364 days of holiday every year. However, the hat has decided that it can do even better—it would like very much to become a tenured professor. Recently the hat has been reading computer science papers in its ample spare time, and of course, being an arranging hat, it is particularly interested in learning more about sorting algorithms.
The hat’s new contribution is to a class of algorithms known as lossy sorting algorithms. These usually work by removing some of the input elements in order to make it easier to sort the input (e.g., the Dropsort algorithm), instead of sorting all the input.
The hat is going to go one better—it is going to invent a lossy sorting algorithm for numbers that does not remove any input numbers and even keeps them in their original place, but instead changes some of the digits in the numbers to make the list sorted.
The lossiness of the sorting operation depends on how many digits are changed. What is the smallest number of digits that need to be changed in one such list of numbers, to ensure that it is sorted?

 

题目大意:给你n个长度为m的正整数,你需要改变最少次数使其成为递增。

思路:明显的dp题,dp[i][j] 表示前i个数改变j次得到的第i个数的最小值,我们可以通过 dp[i][j] 贪心地得到 dp[i+1][j+k] 的最小值,前i个数我们最多可以改变i*m次,那么我们开的数组为 dp[n][n*m][m], 肯定爆空间了。但仔细想想,在最坏的情况下n为40,改变的次数最多也就10*(1+2+3+4)次。为什么?交给读者自己思考。

还有一个坑点,就是在给定次数贪心最小值。思路是从最高位开始贪心,不同的就使它们相等,直至用完次数。用完后发现还是比原数要小,就在改变的最低位加1,但前提是不能为‘9’,如果是9的话就往高位找,直至找到不为9的数令其+1,并且往后填0,当然,如果没有就返回false。

最后就是细节处理要注意了,附AC代码:

 1 #include<bits/stdc++.h>
 2 #define CLR(a, b) memset(a, b, sizeof(a))
 3 
 4 using namespace std;
 5 const int maxn = 40 + 5;
 6 const int maxf = 100 + 5;
 7 const int maxm = 400 + 5;
 8 
 9 char dp[maxn][maxf][maxm];
10 char nm[maxn][maxm];
11 bool val[maxn][maxf];
12 int pre[maxn][maxf];
13 int n, m;
14 
15 bool change(const char *a, const char *b, int lim, char *temp) {
16     strcpy(temp, b);
17     int left = lim;
18     int p = 0;
19     for(p=0;p<m&&left;p++) if(temp[p]!=a[p])
20         temp[p] = a[p], left--;
21     if(strcmp(temp, a)>=0) 
22         return true;
23     left = lim;
24     for(--p;p>=0&&temp[p]=='9';) --p;
25     if(p<0) return false;
26     int pos;
27     strcpy(temp, b);
28     for(pos=0;pos<p;pos++) if(temp[pos]!=a[pos])
29         temp[pos] = a[pos], left--;
30     if(temp[p]-1 != a[p]) {
31         temp[p] = a[p]+1; left --;
32     }
33     for(++p;p<m&&left;p++) {
34         temp[p] = '0';
35         if(temp[p]!=a[p]) left--;
36     }
37     return true;
38 }
39 
40 void print_ans(int nn, int k) {
41     if(!nn) return ;
42     print_ans(nn-1, pre[nn][k]);
43     printf("%s\n", dp[nn][k]);
44 }
45 
46 int main() {
47     scanf("%d%d", &n, &m);
48     for(int i=1;i<=n;i++)
49         scanf("%s", nm[i]);
50     CLR(dp, 0);
51     CLR(val, false);
52     for(int i=0;i<m;i++)
53         dp[0][0][i] = '0';
54     dp[0][0][m] = '\0';
55     val[0][0] = true;
56     char temp[maxm];
57     CLR(pre, 0);
58     for(int i=0;i<n;i++) 
59         for(int j=0;j<maxf;j++) if(val[i][j]) {
60             for(int k=0;k<=m && k+j < maxf;k++) {
61                 if(change(dp[i][j], nm[i+1], k, temp) && 
62                 (!val[i+1][k+j] || strcmp(temp, dp[i+1][k+j]) < 0)) {
63                     val[i+1][k+j] = true;
64                     strcpy(dp[i+1][k+j], temp);
65                     pre[i+1][k+j] = j;
66                 }
67             }
68         }
69     int sign;
70     for(int i=0;i<maxf;i++)
71         if(val[n][i]) { sign = i; break; }
72     print_ans(n, sign);
73 }

 

转载于:https://www.cnblogs.com/UtopioSPH001/p/ycqdp0001.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值