hdu 2577 dp

来源:互联网 发布:sql if两个判断 编辑:程序博客网 时间:2024/06/05 20:09

题目

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2577

题目来源:群赛(462377900)题目
    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=90337#overview

简要题意:要在电脑上输入一串字母S,最后大写要关闭,求最少输入的按键数。

数据范围:T100;|S|100只含大小写

题解

首先想到的是直接模拟,应该很多人都会有这样的第一感觉。

对每个最长大写子串S对加上min(2+|S|,2|S|),对于小写字母直接加。

但是这个WA了一发之后就很容易发现不对了,其实可以在大写开启的时候按Shift的。

接下来就很容易想到可以用dp来解决这个问题了。

考虑每位的状态可能是大写或小写,dp[i][j]即为打完前i个字符状态为j的最少按键数。
不妨让0表示小写,1表示大写。

再考虑状态之间的转移,分情况稍微讨论一下就行了。
当前位置的字符为小写时,转移方程如下:

dp[i][0]dp[i][1]=min(dp[i1][0]+1,dp[i1][1]+2)       =min(dp[i1][1]+2,dp[i1][0]+2)       Shift
当前位置的字符为大写时,转移方程如下,相似地推,就不赘述了:
dp[i][1]dp[i][0]=min(dp[i1][1]+1,dp[i1][0]+2)=min(dp[i1][0]+2,dp[i1][1]+2)


通过观察不难发现这个公式很好化简,设当前位置的大小写状态为c,则有:

dp[i][c]dp[i][1c]=min(dp[i1][c]+2,dp[i1][1c]+2)=min(dp[i1][1c]+1,dp[i1][c]+2) 

最终的答案为dp[|S|][0]

实现

   这个真心没啥好说的,直接推就行了,唯一值得一说的点就是islower(char ch)这一类函数的返回值其实是int,我这种喜欢直接赋值过去的就比较容易被坑了,总结下来还是需要多了解系统的函数。复杂度Θ(|S|)

朴素代码

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define sz(x) ((int)(x).size())#define fi first#define se secondusing namespace std;typedef long long LL;typedef vector<int> VI;typedef pair<int,int> PII;LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}// headconst int INF = 0x3f3f3f3f;char s[105];int dp[105][2];int main(){    int t;    scanf("%d", &t);    while (t--) {        scanf("%s", s+1);        int len = strlen(s+1);        bool flag = false;        memset(dp, INF, sizeof dp);        dp[0][0] = 0;        for (int i = 1; i <= len; i++) {            if (islower(s[i])) {                dp[i][0] = min(dp[i-1][0]+1, dp[i-1][1]+2);                dp[i][1] = min(dp[i-1][1]+2, dp[i-1][0]+2);            } else {                dp[i][1] = min(dp[i-1][1]+1, dp[i-1][0]+2);                dp[i][0] = min(dp[i-1][0]+2, dp[i-1][1]+2);            }        }        printf("%d\n", dp[len][0]);    }    return 0;}

化简代码

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#include <queue>#include <string>#include <vector>#include <set>#include <map>#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define sz(x) ((int)(x).size())#define fi first#define se secondusing namespace std;typedef long long LL;typedef vector<int> VI;typedef pair<int,int> PII;LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}// headconst int INF = 0x3f3f3f3f;char s[105];int dp[105][2];int main(){    int t;    scanf("%d", &t);    while (t--) {        scanf("%s", s+1);        int len = strlen(s+1);        bool flag = false;        memset(dp, INF, sizeof dp);        dp[0][0] = 0;        for (int i = 1; i <= len; i++) {            int c = islower(s[i]) ? 1 : 0;            dp[i][c] = min(dp[i-1][c], dp[i-1][1-c])+2;            dp[i][1-c] = min(dp[i-1][1-c]+1, dp[i-1][c]+2);        }        printf("%d\n", dp[len][0]);    }    return 0;}
0 0