码迷,mamicode.com
首页 > 其他好文 > 详细

第三章答案

时间:2015-03-07 00:56:14      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

地址:http://www.th7.cn/Program/java/201408/253926.shtml

3 习题

3.1 UVa1585--Score

#include int main() {    int T;    scanf("%d", &T);    while (T--) {        char s[100];        scanf("%s", s);        int sum = 0, cnt = 0;        for (int i = 0; s[i]; i++) {            if (s[i]==‘X‘) {                sum += cnt*(cnt+1)/2;                cnt = 0;            }            else cnt++;        }        printf("%d/n", sum+cnt*(cnt+1)/2);    }    return 0;}
每遇到X做一次更新,否则cnt++,注意第19行最后还要一次更新。

看了这段代码:http://blog.csdn.net/sinat_17231979/article/details/36869231后,发现还是想复杂了,没必要用前n项和公式,直接用一个变量记录当前有多少个O就行了:
#include int main() {    int T;    scanf("%d", &T);    while (T--) {        char s[100];        scanf("%s", s);        int sum = 0, cnt = 0;        for (int i = 0; s[i]; i++) {            if (s[i]==‘X‘) cnt = 0;            else {                cnt++;                sum += cnt;            }        }        printf("%d/n", sum);    }    return 0;}

3.2 UVa1586--Molar Mass

暴力每一位i,如果i+1位是数字,判断i+2位是不是数字,分情况计算数量;如果i+1位不是数字,那么数量就是默认的1。接着判断第i位是不是字母,不是则continue,否则累加相应的质量。
#include #include int main() {    int T;    scanf("%d", &T);    while (T--) {        char s[100];        scanf("%s", s);        double sum = 0, w;        for (int i = 0; s[i]; i++) {            // 算出后两位所代表的数值            if (isdigit(s[i+1])) {                if (isdigit(s[i+2])) w = 10*(s[i+1]-‘0‘)+s[i+2]-‘0‘;                else w = s[i+1] - ‘0‘;            }            else w = 1;            // 判断第一位            if (!isalpha(s[i])) continue;            else if (s[i] == ‘C‘) sum += 12.01*w;            else if (s[i] == ‘H‘) sum += 1.008*w;            else if (s[i] == ‘O‘) sum += 16.00*w;            else sum += 14.01*w;        }        printf("%.3lf/n", sum);    }    return 0;}

3.3 UVa1225--Digit Counting

#include int main() {    int T;    scanf("%d", &T);    while (T--) {        int N, i, t, a[10] = {};        scanf("%d", &N);        for (i = 1; i <= N; i++) {            t = i;            while (t) a[t%10]++, t/=10;        }        for (i = 0; i < 9; i++) printf("%d ", a[i]);        printf("%d/n", a[9]);    }    return 0;}
直接每组暴力都能过。如果会TLE,也可以建立二维数组a[10000][10],先暴力一轮求出数据。后面只要打表就行了。

3.4 UVa455--Periodic Strings

算一个字符串的周期,其周期一定是长度的约数,按这一点枚举,并写一个判断T是不是一个字符串的周期的函数(isThePeriod)即可。

输入格式略坑,每两组测试间会有一个空行,所以我用第19行那样的方式解决。

最后注意输出格式,也要每两个隔一个空行~~~
#include #include int isTthePeriod(char s[], int T) {    for (int i = 0; i < T; i++) {        for (int j = i+T; j < strlen(s); j+=T)            if (s[i] != s[j]) return 0;    }    return 1;}int main() {    int T, kase, len, i;    scanf("%d", &T);    for (kase = 1; kase <= T; kase++)    {        char s[100];        while (scanf("%s", s), len = strlen(s), !len);        for (i = 1; i <= len; i++)            if (len%i == 0 && isTthePeriod(s,i)) break;        if (kase != 1) putchar(‘/n‘);        printf("%d/n", i);    }    return 0;}

3.5 UVa227--Puzzle

这题稍微有些麻烦了,模拟操作,我尽量进行了些优化,而且为了方便交换变量,用了C++里algorithm的swap,没有自己写交换函数。【基本框架】将5*5网格定义为全局变量s(从1开始编号),当前空格所在行列为x,youtput函数用来输出s的矩阵形式ok用来操作一个命令为ch的移动,返回值1代表操作成功,返回0代表失败。成功的话,要更新相应的x、y和进行交换操作swaptest用来完成每组测试的操作 总结:对于复杂的问题,要想清思路,然后把大问题划分成一个个小的子问题去求解。
#include #include using namespace std;int x, y;char s[6][6];void output() {    for (int i = 1; i <= 5; i++) {        for (int j = 1; j < 5; j++)            printf("%c ", s[i][j]);        printf("%c/n", s[i][5]);    }}int ok(char ch) {    switch (ch) {    case ‘A‘:        if (x == 1) return 0; else x--;        swap(s[x][y], s[x+1][y]); break;    case ‘B‘:        if (x == 5) return 0; else x++;        swap(s[x][y], s[x-1][y]); break;    case ‘L‘:        if (y == 1) return 0; else y--;        swap(s[x][y], s[x][y+1]); break;    case ‘R‘:        if (y == 5) return 0; else y++;        swap(s[x][y], s[x][y-1]); break;    }}int test() {    char ch;    int i, j;    for (i = 1; i <= 5; i++) for (j = 1; j <= 5; j++)        if (s[i][j] == ‘ ‘) x = i, y = j;    while ((ch = getchar()) != ‘0‘) {        if (ch == ‘/n‘) continue;        if (!ok(ch)) {  // 非法操作,仍要清掉字符‘0‘前的值            while (getchar() != ‘0‘);            return 0;        }    }    return 1;}int main() {    int kase, i, j;    for (kase = 1; ; kase++) {        gets(&s[1][1]);        if (s[1][1] == 0) {kase--; continue;}   // 注意此处读到空串,要忽略读入continue        if (s[1][1] == ‘Z‘ && s[1][2] == 0) break;        if (kase != 1) putchar(‘/n‘);        printf("Puzzle #%d:/n", kase);        for (i = 2; i <= 5; i++) gets(&s[i][1]);        if (test()) output();        else printf("This puzzle has no final configuration./n");    }    return 0;}

3.6 UVa232--Crossword Answers

这题就是像中学英语填单词的那种网格。需要对起始点编号,然后按行输出、再按列输出所有单词。
#include #include int main() {    int n, m, a[15][15], k, i, j;    char s[15][15];    for (int kase = 1; ; kase++) {        if (scanf("%d%d ", &n, &m) != 2) break;        k = 0;        memset(a, 0, sizeof(a));        memset(s, 0, sizeof(s));        for (i = 1; i <= n; i++) gets(&s[i][1]);        for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) {            if (s[i][j] == ‘*‘) s[i][j] = 0;            if (!(s[i-1][j]&&s[i][j-1]) && s[i][j]) a[i][j] = ++k;        }        if (kase != 1) putchar(‘/n‘);        printf("puzzle #%d:/nAcross/n", kase);        for (i = 1; i <= n; i++) for (j = 1; j <= m; j++)            if (s[i][j] && !s[i][j-1]) printf("%3d.%s/n", a[i][j], s[i]+j);        printf("Down/n");        for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) {            if (s[i][j] && !s[i-1][j]) {                printf("%3d.", a[i][j]);                for (k = i; s[k][j]; k++) putchar(s[k][j]);                putchar(‘/n‘);            }        }    }    return 0;}

3.7 UVa1368--DNA Consensus

思路:找出每列中ACGT出现次数最多的字符,就是最优解序列在这一列的字符值。
#include #include inline int c2d(char c) {    if (c == ‘A‘) return 0;    else if (c == ‘C‘) return 1;    else if (c == ‘G‘) return 2;    else return 3;}inline int d2c(int d) {    if (d == 0) return ‘A‘;    else if (d == 1) return ‘C‘;    else if (d == 2) return ‘G‘;    else return ‘T‘;}int main() {    int T, m, n, i, j, a[1010][4], sum;    char s[50][1010];    scanf("%d", &T);    while (scanf("%d%d ", &m, &n) == 2) {        for (i = 0; i < m; i++) gets(s[i]);        memset(a, 0, sizeof(a));        for (i = 0; i < m; i++) for (j = 0; j < n; j++)            a[j][ c2d(s[i][j]) ]++;        for (sum = j = 0; j < n; j++) {            int the_max = a[j][0], id = 0;            for (i = 1; i < 4; i++) if (a[j][i]>the_max)                id = i, the_max = a[j][i];            putchar(d2c(id));            sum += m - the_max;        }        printf("/n%d/n", sum);    }    return 0;}

3.8 UVa202--Repeating Decimals

这题需要模拟除法,当出现相同的余数时,就代表循环点的出现。下面我以5/7为例详细的讲下思路。技术分享
如上图,第0步,分子是5,分母是7(分母在整个除法中始终不变),5/7的商是0,代表这个除法的整数部分是0,,余数是5,乘以10,得50作为第1步的分子;50/7的商为7,代表这个除法的第一位小数是7,余数是1,乘以10,得10作为第2步的分子...可以发现每步的除法只跟分子有关,也就是当分子出现重复值,如上图第1步和第7步的分子值都为50时,第7步后面的运算其实是在重复第1步至第6步间的运算。所以第1步至第7步就是一个循环节。 程序实现中,可以不用存储余数的值,只需存储上图中的分子和商,我定义了A[2][3010],用A[0][j]存储第j步的分子,A[1][j]存储第j步的商。注意最后的数值由商可以直接构成,如上图的红色字体,数值为0.7142857142...
#include int A[2][3010], p, q;// 找i位之前是否有重复分子出现;有则返回周期,否则返回-1.inline int myfind() {    for (p = 1; p < q; p++) {        if (A[0][p] == A[0][q])            return q - p;    }    return -1;}int main() {    int kase, a, b, i, len;    for (kase = 1; scanf("%d%d", &a, &b) != EOF; kase++) {        A[0][0] = a; A[1][0] = a/b;        for (q = 1; ; q++) {            A[0][q] = (A[0][q-1] - b*A[1][q-1])*10;            A[1][q] = A[0][q]/b;            len = myfind();            if (len > 0) break;        }        printf("%d/%d = %d.", a, b, A[1][0]);        for (i = 1; i < p; i++) printf("%d", A[1][i]);        putchar(‘(‘);        for (i = p; i < q; i++) {            if (i > 50) {                printf("...");                break;            }            printf("%d", A[1][i]);        }        printf(")/n   %d = number of digits in repeating cycle/n/n", len);    }}

3.9 UVa10340--All in All

遍历后者,找前者往后是否有对应的字符。
#include #include using namespace std;int fun(string& a, string& b) {    int i, j = 0;    for (i = 0; i < a.size(); i++, j++) {        while (j < b.size() && a[i]!=b[j]) j++;        if (j == b.size()) return 0;    }    return 1;}int main() {    string a, b;    while (cin >> a >> b) {        if (fun(a,b)) cout << "Yes/n";        else cout << "No/n";    }}

3.10 UVa1587--Box

只要用一堆疯狂的条件分支就能解答此题了:http://blog.csdn.net/u013451221/article/details/37672039。不过这里我更乐意把数据“标准化”,然后用C++构造“Face类”来求解。 首先构造一个宽w一定不小于高h的“面类(Face)”,并且按h为第一级,w为第二级准则从小到大排序。如果是能组成长方体的,边长肯定只有三种值,不妨设从小到大依次为a,b,c。则输入的6个面排序后,一定满足以下分布:
技术分享vczltcSz5NKqzPW8/qGjCjxwcmUgY2xhc3M9"brush:java;">#include #include #includeusing namespace std;struct Face{ int h, w; void make(int x, int y) { h = min(x,y); w = max(x,y); } bool operator < (const Face& b) const { if (h == b.h) return w < b.w; else return h < b.h; } bool operator == (const Face& b) const { return (h == b.h) && (w == b.w); }};vector A(6);int test1() { for (int i = 0; i < 6; i += 2) if (!(A[i]==A[i+1])) return 0; return 1;}int test2() { if (A[0].h==A[2].h && A[0].w==A[4].h && A[2].w==A[4].w) return 1; else return 0;}int main() { int x, y; while (cin >> x >> y) { A[0].make(x, y); for (int i = 1; i < 6; i++) { cin >> x >> y; A[i].make(x, y); } sort(A.begin(), A.end()); if (test1() && test2()) cout << "POSSIBLE/n"; else cout << "IMPOSSIBLE/n"; } return 0;}

3.11 UVa1588--Kickdown

假设固定装置s1,那么装置s2只要初始状态左端与s1左端对齐(该状态用偏移量k=0来标记),然后测试k=0时,两个装置是不是”每一位的和都不会超过3“就行了,如果不行就k++,继续往右边偏移进行测试。可以知道肯定存在着一个k能使其成立的(也就是s2左端接在s1右端时)。用这种方式遍历,找到的第一个可行解就是最佳解。 不过上述讨论还遗漏了一种组合方式,就是s2也可以往左偏移。其实将上述解法写成一个fun函数进行封装,外界(main函数)只要巧妙的利用对称性,就能重复利用上一段的代码了。
#include #include #include using namespace std;int len1, len2;char s1[110], s2[110];int test(int k, char s1[], char s2[]) {    for (int i = 0; s1[k+i] && s2[i]; i++)        if (s1[k+i]+s2[i]-2*‘0‘ > 3) return 0;    return 1;}int fun(char s1[], char s2[]) {    int k = 0;    while (!test(k,s1,s2)) k++;    return max(strlen(s1), strlen(s2)+k);}int main() {    while (scanf("%s%s", s1, s2) != EOF) {        printf("%d/n", min(fun(s1,s2), fun(s2,s1)));    }    return 0;}

3.12 UVa11809--Floating-Point Numbers

首先要知道二进制小数的原理:技术分享
本题的思路就是先把所有的M、E对应的值算出来,记为矩阵C,其中C[M,E]=尾数M、阶码E对应的最大值。然后对于输入的AeB,找出C中与其相等的值所在的行M、列E即是答案。 不过这里有两个要点。一是这个数值太大,可以达到2^(2^30-1),远超了double的存储范围。所以我们不妨对数值做一个变换,取以10为底的对数值来存储。二是计算过程的舍尾误差与double本身存在的误差会导致精度问题。所以可以在矩阵C中找与输入值最接近的作为匹配点,也就是差值的绝对值最小。
最后还有M=0,E=1的特殊点,在程序中会出现0.0-0.0<0.0条件为否的错误,导致pi,pj无法更新,这个问题只要把pi、pi分别初始化为0、1就能解决了。
#include #include #include double C[10][31];void init() {    int i, j, v;    double f[10] = {0.5}, g[31], t;    for (i = 1, t = 0.5; i < 10; i++) {        f[i] = f[i-1] + t/2;        t /= 2;    }    for (i = 0; i < 10; i++) f[i] = log10(f[i]);    for (i = 1, v = 2; i <= 30; i++) {        g[i] = (v - 1.0)*log10(2.0);        v <<= 1;    }    for (i = 0; i < 10; i++) for (j = 1; j <= 30; j++)        C[i][j] = f[i] + g[j];}int main() {    int i, j;    char s[100], *p;    double A, B;    init();    while (scanf("%s", s), strcmp(s, "0e0")) {        p = strchr(s, ‘e‘);        *p = 0;                 // 将‘e‘所在位置变为‘/0‘        sscanf(s, "%lf", &A);        sscanf(p+1, "%lf", &B);        int pi = 0, pj = 1;        B = A = log10(A) + B;   // 接下来A存储表达式值,B记录差值        for (i = 0; i < 10; i++) for (j = 1; j <= 30; j++)        if (fabs(A-C[i][j]) < B) pi = i, pj = j, B = fabs(A-C[i][j]);        printf("%d %d/n", pi, pj);    }    return 0;}

第三章答案

标签:

原文地址:http://www.cnblogs.com/travelller/p/4319557.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!