算法入门经典2 第3章解题报告

来源:互联网 发布:贵州云博大数据 编辑:程序博客网 时间:2024/05/17 04:58

【写在前面】 就不写题意了,紫书上面有中文翻译,下面水题我直接给出代码了,一些需要推导的详细写一下!

【3-1】水题,顺序扫描一遍就行了。复杂度O(len)

char s[82];bool vis[82];int main(){    int T;    scanf("%d",&T);    REP(i, T){        memset(vis, false, sizeof(vis));        scanf("%s", s);        int ans = 0;        int len = strlen(s);        REP(i, len){            if(vis[i] || s[i] == 'X') continue;            int cnt = 0;            while(s[i] == 'O'){                vis[i] = true;                cnt++, i++;            }            ans += cnt * (cnt + 1) / 2;        }        printf("%d\n", ans);    }    return 0;}

【3-2】同水题,模拟一下即可。复杂度O(len)

map<char, double> mp;char s[20];int main(){    mp['C'] = 12.01, mp['H'] = 1.008, mp['O'] = 16.00, mp['N'] = 14.01;    int T;    scanf("%d", &T);    REP(j, T)    {        scanf("%s", s);        int len = strlen(s);        double ans = 0;        REP(i, len){            if(isdigit(s[i])) continue;            if(isdigit(s[i+1])){                double cnt = s[i+1] - '0';                int j = i + 2;                while(isdigit(s[j])){                    cnt = cnt * 10 + s[j] - '0';                    j++;                }                ans += cnt * mp[s[i]];            }            else{                ans += mp[s[i]];            }        }        printf("%.3f\n", ans );    }    return 0;}

【3-3】把所有的数字放到数组里面,或者边循环边基数都可以。

int a[100010];int b[10];int main(){    int T, n;    scanf("%d", &T);    REP(k, T){        int cnt = 0;        scanf("%d", &n);        memset(b, 0, sizeof(b));        for(int i = 1; i <= n; i++){            int j = i;            while(j){                a[cnt++] = j % 10;                j /= 10;            }        }        for(int i = 0; i < cnt; i++){            b[a[i]]++;        }        for(int i = 0; i < 9; i++){            printf("%d ", b[i]);        }        printf("%d\n", b[9]);    }    return 0;}

【3-4】模拟长度并判断,复杂度O(n^2)

char s[82];int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%s", s);        int len = strlen(s);        int ans;        for(int i = 1; i <= len; i++){            bool ok = 1;            string temp = "";            for(int j = 0; j < i; j++) temp += s[j];            for(int j = i; j < len; j += i){                string xx = "";                for(int k = j; k < i + j; k++){                    xx += s[k];                }                if(xx != temp){                    ok = 0;                    break;                }            }            if(ok){                ans = i;                break;            }        }        if(T >= 1)            printf("%d\n\n", ans);        else{            printf("%d\n",ans);        }    }    return 0;}

【3-5】纯模拟,没啥说的!

char maze[5][5];char ope[1010];bool judge(int x, int y){    if(x >= 0 && x < 5 && y >= 0 && y < 5) return true;    else return false;}int main(){    int ks = 0;    while(gets(maze[0])){        if(maze[0][0] == 'Z') break;        gets(maze[1]);        gets(maze[2]);        gets(maze[3]);        gets(maze[4]);        for(int i = 0; i < 5; i++){            if(maze[i][4] == '\0'){                maze[i][4] = ' ';            }        }        int cnt = 0;        while(~scanf("%c", &ope[cnt])){            if(ope[cnt] != '0') cnt++;            else break;        }        ope[cnt++] = '0'; getchar();        int sx, sy;        for(int i = 0; i < 5; i++){            for(int j = 0; j < 5; j++){                if(maze[i][j] == ' '){                    sx = i, sy = j;                }            }        }        bool ok = 1;        int len = strlen(ope);        REP(i, len){            if(ope[i] == '0') break;            if(ope[i] == 'L'){                if(judge(sx, sy - 1)){                    maze[sx][sy] = maze[sx][sy-1];                    maze[sx][sy-1] = ' ';                    sy--;                }                else{                    ok = 0;                    break;                }            }            if(ope[i] == 'R'){                if(judge(sx, sy + 1)){                    maze[sx][sy] = maze[sx][sy+1];                    maze[sx][sy+1]=' ';                    sy++;                }                else{                    ok = 0;                    break;                }            }            if(ope[i] == 'A'){                if(judge(sx-1, sy)){                    maze[sx][sy] = maze[sx-1][sy];                    maze[sx-1][sy] = ' ';                    sx--;                }                else{                    ok = 0;                    break;                }            }            if(ope[i] == 'B'){                if(judge(sx+1, sy)){                    maze[sx][sy] = maze[sx+1][sy];                    maze[sx+1][sy] = ' ';                    sx++;                }                else{                    ok = 0;                    break;                }            }        }        if(ks++) printf("\n");        printf("Puzzle #%d:\n", ks);        if(ok == 0){            printf("This puzzle has no final configuration.\n");        }        else{           for(int i = 0; i < 5; i++){                for(int j = 0; j < 4; j++){                    printf("%c ",maze[i][j]);                }                printf("%c\n",maze[i][4]);           }        }    }    return 0;}

【3-6】纯模拟,不过输出要按照序号排序之后再输出。格式有点坑,pe了很多发。

int n, m;char maze[12][12];int id[12][12];bool check(int x, int y){    if(x >= 0 && x < n && y >= 0 && y < m){        return true;    }    else{        return false;    }}struct node{    int pos;    string s;    bool operator<(const node &rhs) const{        return pos < rhs.pos;    }    void init(){        pos = 0;        s = "";    }}ans[110];int main(){    int ks = 1;    while(scanf("%d", &n), n)    {        scanf("%d", &m);        for(int i = 0; i < n; i++){            scanf("%s", maze[i]);        }        for(int i = 0; i < 110; i++){            ans[i].init();        }        int cntt = 0;        memset(id, 0, sizeof(id));        int cnt = 0;        for(int i = 0; i < n; i++){            for(int j = 0; j < m; j++){                if(maze[i][j] == '*') continue;                if((check(i-1, j) == false || maze[i-1][j] == '*') || (check(i, j-1) == false || maze[i][j-1] == '*')){                    id[i][j] = ++cnt;                }            }        }        if(ks>1) printf("\n");        printf("puzzle #%d:\n", ks++);        printf("Across\n");        int k;        for(int i = 0; i < n; i++){            for(int j = 0; j < m; j += k){                if(id[i][j] != 0){                    //printf("  %d.", id[i][j]);                    ans[cntt].pos = id[i][j];                    k = 0;                    while( maze[i][j+k] != '*' && (j + k) < m){                        //printf("%c", maze[i][j+k]);                        ans[cntt].s += maze[i][j+k];                        k++;                    }                    //printf("\n");                    cntt++;                }                else{                    k = 1;                }            }        }        sort(ans, ans+cntt);        for(int i = 0; i < cntt; i++){            printf("%3d.",ans[i].pos);            cout<<ans[i].s<<endl;        }        cntt = 0;        for(int i = 0; i < 110; i++){            ans[i].init();        }        printf("Down\n");        for(int i = 0; i < m; i++){            for(int j = 0; j < n; j += k){                if(id[j][i] != 0){                    //printf("  %d.", id[j][i]);                    ans[cntt].pos = id[j][i];                    k = 0;                    while(maze[j+k][i] != '*' && (j + k) < n){                        //printf("%c", maze[j+k][i]);                        ans[cntt].s += maze[j+k][i];                        k++;                    }                    cntt++;                    //printf("\n");                }                else{                    k = 1;                }            }        }        sort(ans, ans+cntt);        for(int i = 0; i < cntt; i++){            printf("%3d.",ans[i].pos);            cout<<ans[i].s<<endl;        }    }    return 0;}

【3-7】贪心,找每一列出现最多的那个字母!复杂度O(n*m)

char s[1002];struct node{    int a, c, g, t;    void init(){        a = 0, c = 0, g = 0, t = 0;    }}thing[1005];int main(){    int T, n, m;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        for(int i = 0; i < m; i++){            thing[i].init();        }        for(int i = 0; i < n; i++){            scanf("%s", s);            for(int j = 0; j < m; j++){                if(s[j] == 'A') thing[j].a++;                else if(s[j] == 'C') thing[j].c++;                else if(s[j] == 'G') thing[j].g++;                else thing[j].t++;            }        }        char ans[1005] = {'0'};        int maxx, anss = 0;        for(int i = 0; i < m; i++){            ans[i] = 'A';            maxx = thing[i].a;            if(thing[i].c > maxx){                ans[i] = 'C';                maxx = thing[i].c;            }            if(thing[i].g > maxx){                ans[i] = 'G';                maxx = thing[i].g;            }            if(thing[i].t > maxx)            {                ans[i] = 'T';                maxx = thing[i].t;            }            anss += n - maxx;        }        ans[m] = '\0';        printf("%s\n", ans);        printf("%d\n", anss);    }    return 0;}

【3-8】计算循环节。n除以m的余数只能是0~m-1,根据抽屉原则,当计算m+1次时至少存在一个余数相同, 即为循环节;存储余数和除数,输出即可。复杂度O(m)

int a[3003], b[3003], c[3003];int main(){    int n, m, t;    while(scanf("%d%d", &n, &m) != EOF)    {        t = n;        memset(a, 0, sizeof(a));        memset(b, 0, sizeof(b));        memset(c, 0, sizeof(c));        int cnt = 0;        a[cnt++] = n/m;        n = n % m;        while(!b[n] && n){            b[n] = cnt; //记录第一次出现的位置            c[cnt] = n;            a[cnt++] = 10*n/m;            n = 10*n%m;        }        printf("%d/%d = %d.", t, m, a[0]);        for(int i = 1; i < cnt && i <= 50; i++){            if(n && c[i] == n) printf("(");            printf("%d", a[i]);        }        if(n == 0) printf("(0");        if(cnt > 50) printf("...");        printf(")\n");        printf("   %d = number of digits in repeating cycle\n\n", n == 0 ? 1 : cnt - b[n]);    }    return 0;}

【3-9】满足单调性,O(n扫描一下文本串即可!


char s1[100010], s2[100010];int main(){    while(scanf("%s%s", s1,s2) != EOF)    {        int len1 = strlen(s1);        int len2 = strlen(s2);        int p = 0;        if(len1 > len2){            printf("No\n");            continue;        }        for(int i = 0; i < len2; i++){            if(s2[i] == s1[p]){                p++;            }        }        if(p == len1){            printf("Yes\n");        }        else{            printf("No\n");        }    }    return 0;}

【3-10】根据长方体的特点去判断即可!

struct Plane{    int x, y;    bool operator<(const Plane &rhs) const{        if(x == rhs.x) return y > rhs.y;        return x > rhs.x;    }}p[6];bool judge(){    if(memcmp(p, p + 1, sizeof(Plane)) || memcmp(p + 2, p + 3, sizeof(Plane)) || memcmp(p + 4, p + 5, sizeof(Plane))) return false;    if(p[0].x != p[2].x || p[0].y != p[4].x || p[2].y != p[4].y) return false;    return true;}int main(){    while(scanf("%d%d",&p[0].x,&p[0].y) != EOF)    {        if(p[0].x < p[0].y) swap(p[0].x, p[0].y);        for(int i = 1; i < 6; i++){            scanf("%d%d",&p[i].x,&p[i].y);            if(p[i].x < p[i].y){                swap(p[i].x, p[i].y);            }        }        sort(p, p + 6);        if(judge()){            printf("POSSIBLE\n");        }        else{            printf("IMPOSSIBLE\n");        }    }    return 0;}

【3-11】固定一个不变,移动宁一个,判断合法性,取最小值 复杂度O(max(len1, len2))

char s1[200], s2[200];int len1, len2;int solve(char *s1, char *s2, int n){    int sumlen = len1 + len2;    int minn = min(len1, len2);    int len = sumlen;    REP(i, n){        int ok = 1, lcm = min(n - i, minn);        REP(j, lcm){            if(s1[i + j] == '2' && s2[j] == '2'){                ok = 0;                break;            }        }        if(ok && len > sumlen - lcm){            len = sumlen - lcm;        }    }    return len;}int main(){    while(scanf("%s%s",s1,s2)!=EOF)    {        len1 = strlen(s1);        len2 = strlen(s2);        int ans = min(solve(s1, s2, len1), solve(s2, s1, len2));        printf("%d\n", ans);    }    return 0;}

【3-12】

如果每组数都要计算比较找到对应的m和e运算量太大,所以先打表,涉及浮点数表示的一些数学知识。  假设当前一层M和E的值为m和e,它们的位数分别为i和j。  首先计算m的值,用二进制表示的话,m的值为0.11…,也就是m = 2^(-1) + 2^(-2) + … + 2^(-1 - i)(i比实际1的个数少1个),也就是m = 1 - 2^(-1 - i)。  接下来就是计算e的值,不难得出,e = 2^j - 1。  那么也就有m * 2^e = A * 10^B,似乎可以直接计算了。然而,直接这样算的话是不行的,因为当e太大的话(e最大可以是1073741823,注意这还只是2的指数),等号左边的数就会超出上限,所以要想继续算下去,就得自己去想办法再写出满足要求的类来,这显然太麻烦了。所以,这个时候我们对等式两边同时取对数,这个时候就有 log10(m) + e × log10(2) = log10(A) + B。因为此时m和e的值都是确定的,所以不妨令等式左边为t,也就有t = log10(A) + B。  这个时候就有问题了,A和B怎么算。  科学记数法对于A,有1 ≤ A < 10。那么0 < log10(A) < 1。所以t的小数部分就是log10(A),整数部分就是B,即B = ⌊t⌋,A = 10^(t - B)。那么接下来,我们只需要开出两个二维数组来,分别记录对应i和j下A和B的大小,之后从输入里提取出A和B的大小,去二维数组里面查找对应的i和j即可。编程知识:  1.如果浮点数赋值给整数,小数部分会被截取。  2.类似这样5.699141892149156e76的数据串,想把e两端的数据分别赋给两个变量,可以先用string接收整个数据串,将string中的'e'替换为‘ ’,再将string拷贝到istringstream的一个对象,再从该对象读取到两个变量即可。


double A[20][40];long B[20][40];string s;void init(){    REP(m, 9){        REPZ(e, 30){            double x = 1 - pow(2, -1 - m), y = pow(2, e) - 1;            double t = log10(x) + y*log10(2);            B[m][e] = t;            A[m][e] = pow(10, t - B[m][e]);        }    }}int main(){    init();    while(cin>>s){        if(s == "0e0") break;        for(auto it = s.begin(); it != s.end(); it++){            if(*it == 'e'){                *it = ' ';                break;            }        }        istringstream is(s);        double a;        long b;        bool ok = 0;        is>>a>>b;        REP(m, 9){            REPZ(e, 30){                if(b == B[m][e] && (fabs(a - A[m][e]) < 1e-5)){                    cout<<m<<" "<<e<<endl;                    ok = 1;                    break;                }            }            if(ok) break;        }    }    return 0;}


0 0
原创粉丝点击