【题解】 —算法竞赛入门经典第二版 【第三章习题】【12/12】

UVa 1585 Score 【字符串】【模拟】【基础】

题目大意:

给定一个由O和X组成的字符串,每个O都有一定的分数,是目前连续出现的O的个数,问这个字符串的得分是多少。

解题思路:

直接做。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

int t, res, tem;
string s;
int main()
{
cin >> t;
while(t--)
{
cin >> s;
res = 0;
tem = 0;
for(int i = 0; i < s.size(); ++i)
{
if(s[i] == 'O')
++tem;
else
tem = 0;
res += tem;
}
cout << res << "\n";
}
return 0;
}

UVa 1586 Molar mass【字符串】【模拟】【基础】

题目大意:

给出一个物质的分子式,求分子量。

解题思路:

直接做。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

string s;
int t, tem;
double res;
double Q(char ch)
{
if(ch == 'C') return 12.01;
if(ch == 'H') return 1.008;
if(ch == 'O') return 16.00;
return 14.01;
}
int main()
{
cin >> t;
while(t--)
{
cin >> s;
res = 0;
tem = 0;
for(int i = 0; i < s.size(); ++i)
{
if(isalpha(s[i]))
{
tem = 1;
int j = 1;
while(isdigit(s[i + j]))
{
if(j == 1) tem = 0;
tem = tem * 10 + (s[i + j] - '0');
++j;
}
res += Q(s[i]) * tem;
}
}
printf("%.3f\n", res);
}
return 0;
}

UVa 1225 Digit Counting【模拟】【基础】

题目大意:

将前n个数字顺次写到一起,问1 ~ 9 各出现多少次。

解题思路:

直接做。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

int t, n, a[11];
void solve(int x)
{
while(x)
{
++a[x % 10];
x /= 10;
}
}
int main()
{
cin >> t;
while(t--)
{
cin >> n;
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; ++i)
solve(i);
for(int i = 0; i < 10; ++i)
printf("%d%c", a[i], i == 9 ? '\n' : ' ');
}
return 0;
}

UVa 455 Periodic Strings【字符串】【模拟】【基础】

题目大意:

如果一个字符串可以通过某个长度为k的字符串多次重复得到,那么称该串以k为周期。给一个字符串,问其最小周期是多少。

解题思路:

直接做。枚举答案。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

string s;
int t, res, len;
bool judge(int x)
{
for(int i = x; i < len; ++i)
{
if(s[i] != s[i % x])
return false;
}
return true;
}
int main()
{
cin >> t;
while(t--)
{
cin >> s;
len = s.size();
res = len;
for(int i = 1; i < len; ++i)
{
if((len % i == 0) && judge(i))
{
res = i;
break;
}
}
cout << res << "\n";
if(t) cout << "\n";
}
return 0;
}

UVa 227 Puzzle【字符串】【模拟】【基础】

题目大意:

根据指令完成对应操作。注意字符的读入。

解题思路:

直接做。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

char op;
string s[6];
int nowx, nowy;
void FindNowIdx()
{
for(int i = 0; i < 5; ++i)
for(int j = 0; j < 5; ++j)
if(s[i][j] == ' ' || s[i][j] == '\0')
{
nowx = i;
nowy = j;
return ;
}
}
void Debug()
{
cout << "\n\n******Debug******\n";
for(int i = 0; i < 5; ++i)
cout << s[i] << "\n";
cout << nowx << " " << nowy << "\n";
cout << "******Debug******\n\n";
}
int main()
{
int cas = 0;
while(getline(cin, s[0]) && s[0][0] != 'Z')
{
for(int i = 1; i < 5; ++i)
getline(cin, s[i]);
FindNowIdx();
// Debug();
bool flag = true;
while(cin >> op && op != '0')
{
// cout << "op = " << op << "\n";
if(op == 'A')
{
if(nowx == 0)
flag = false;
else
{
swap(s[nowx][nowy], s[nowx-1][nowy]);
--nowx;
}
}
else if(op == 'B')
{
if(nowx == 4)
flag = false;
else
{
swap(s[nowx][nowy], s[nowx+1][nowy]);
++nowx;
}
}
else if(op == 'L')
{
if(nowy == 0)
flag = false;
else
{
swap(s[nowx][nowy], s[nowx][nowy-1]);
--nowy;
}
}
else if(op == 'R')
{
if(nowy == 4)
flag = false;
else
{
swap(s[nowx][nowy], s[nowx][nowy+1]);
++nowy;
}
}
}
if(cas) cout << "\n";
printf("Puzzle #%d:\n", ++cas);
if(flag)
{
for(int i = 0; i < 5; ++i)
{
for(int j = 0; j < 5; ++j)
{
if(j) cout << " ";
cout << s[i][j];
}
cout << "\n";
}
}
else
cout << "This puzzle has no final configuration.\n";
getchar();
}
return 0;
}

UVa 232 Crossword Answers【模拟】

题目大意:

将格子里的单词按照要求的顺序输出。

解题思路:

算是“预处理”吧,把每个单词的起始位置标记出来,然后再确定是横向还是纵向。我用map先存下单词再输出,其实可以直接输出的。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
const int N = 15;

int a[N][N];
char s[N][N];
bool cro[N][N], dow[N][N];

bool check(int i, int j)
{
if(i == 0 || j == 0) return true;
if(s[i-1][j] == '*' || s[i][j-1] == '*') return true;
return false;
}

int main()
{
int n, m;
int cas = 0;
while(cin >> n && n)
{
if(cas) puts("");

cin >> m;
memset(s, 0, sizeof(s));
memset(a, 0, sizeof(a));

for(int i = 0; i < n; ++i)
scanf("%s",s[i]);

int tot = 0;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
if(s[i][j] != '*' && check(i, j))
a[i][j] = ++tot;
}
}

/*puts("");
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
cout << a[i][j] << " ";
}
puts("");
}*/

map<int, string> mapc;
map<int, string> mapd;
string tem;
memset(cro, false, sizeof(cro));
memset(dow, false, sizeof(dow));
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
if(a[i][j] && !cro[i][j])
{
tem = "";
int k;
for(k = j; k < m;++k)
{
if(s[i][k] == '*') break;
if(cro[i][k]) break;
cro[i][k] = true;
tem += s[i][k];
}
// cout << a[i][j] << " ";
// cout << " tem=" << tem << endl;
mapc[a[i][j]] = tem;
}
}
}

for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
if(a[i][j] && !dow[i][j])
{
tem = "";
int k;
for(k = i; k < n;++k)
{
if(s[k][j] == '*') break;
if(dow[k][j]) break;
dow[k][j] = true;
tem += s[k][j];
}
// cout << a[i][j] << " ";
// cout << "tem=" << tem << endl;
mapd[a[i][j]] = tem;
}
}
}


printf("puzzle #%d:\n",++cas);
puts("Across");
for(auto it = mapc.begin(); it != mapc.end(); ++it)
{
printf("%3d",it->first);
//cout << " " << it -> first
cout << "." << it -> second << endl;
}

puts("Down");
for(auto iter = mapd.begin(); iter != mapd.end(); ++iter)
{
printf("%3d",iter->first);
//cout << " " << iter -> first
cout << "." << iter -> second << endl;
}

}
return 0;
}

UVa 1368 DNA Consensus String【模拟】【构造】

题目大意:

给出n个长度为m的DNA序列,要你构造出一个和他们之间Hamming距离最小的一个DNA序列,如果存在多解,输出字典序最小的那个。

解题思路:

直接砍每个位置上哪个字母出现次数最多,出现次数相等时选字典序小的那个作为解。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1111;
const int M = 55;

int t, n, m, a[5];
char DNA[M][N];

int main()
{
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &n,&m);
for(int i = 0; i < n; ++i)
scanf("%s", DNA[i]);

int cost = 0;
for(int j = 0; j < m; ++j)
{
memset(a, 0, sizeof(a));
for(int i = 0; i < n; ++i)
{
if(DNA[i][j] == 'A') ++a[1];
if(DNA[i][j] == 'C') ++a[2];
if(DNA[i][j] == 'G') ++a[3];
if(DNA[i][j] == 'T') ++a[4];
}
if(a[1] >= a[2] && a[1] >= a[3] && a[1] >= a[4])
putchar('A'), cost += a[2] + a[3] + a[4];
if(a[2] > a[1] && a[2] >= a[3] && a[2] >= a[4])
putchar('C'), cost += a[1] + a[3] + a[4];
if(a[3] > a[2] && a[3] > a[1] && a[3] >= a[4])
putchar('G'), cost += a[2] + a[1] + a[4];
if(a[4] > a[2] && a[4] > a[3] && a[4] > a[1])
putchar('T'), cost += a[2] + a[3] + a[1];
}
putchar('\n');
printf("%d\n", cost);
}
return 0;
}

UVa 202 Repeating Decimals【模拟】【高精度】

题目大意:

将分数化为小数,并且输出循环的长度。

解题思路:

类似高精度,用数组不断记录就可以。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 3005;

int cx[MAX];
int fs[MAX];
int main()
{
int n, m, t, i;
int cou, cas = 0;
while(cin >> n >> m)
{
cou = 0;
memset(cx, 0, sizeof(cx));
memset(fs, 0, sizeof(fs));
printf("%d/%d = %d.",n, m, n/m);

t = n;
while(1)
{
t = t % m * 10;
fs[cou] = t / m;
for(i = 0; i < cou; ++i)
if(cx[i] == t) break;
if(i != cou) break;
cx[cou++] = t;
}

for(int q = 0; q < i; ++q)
cout << fs[q];
cout << "(";

if(cou > 50)
{
for(int q = i; q < i+50; ++q)
cout << fs[q];
cout << "...)\n";
}
else
{
for(int q = i; q < cou; ++q)
cout << fs[q];
cout << ")\n";
}
printf(" %d = number of digits in repeating cycle\n\n", cou-i);
}
return 0;
}

UVa 10340 All in All【模拟】【基础】

题目大意:

两个字符串s1和s2,问能否从s2中删掉若干字符得到s1。

解题思路:

直接做。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 111111

char s1[N],s2[N];
int main()
{
int len1, len2;
while(~scanf("%s %s",s1,s2))
{
len1 = strlen(s1);
len2 = strlen(s2);
int j = 0;
for(int i = 0; i < len2; ++i)
{
if(s1[i] == s2[j]) ++j;
}
if(j == len1)
puts("Yes");
else
puts("No");
}
return 0;
}

UVa 1587 Box【模拟】【基础】

题目大意:

给出6个矩形的长和宽,问能否构成一个矩形。

解题思路:

排序后直接判断就行。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
struct node
{
int w, h;
} ss[10];
bool cmp(node a, node b)
{
if(a.w == b.w)
return a.h < b.h;
return a.w < b.w;
}
int main()
{
int a, b;
while(cin >> a >> b)
{
ss[0].w = min(a, b);
ss[0].h = max(a, b);
for(int i = 1; i<6; ++i)
{
cin >> a >> b;
ss[i].w = min(a, b);
ss[i].h = max(a, b);
}
sort(ss, ss+6, cmp);
/*for(int i = 0; i < 6; ++i)
cout << ss[i].w << " " << ss[i].h << endl;*/
bool flag = true;;
int i;
for(i = 0; i < 6; i += 2)
{
if(ss[i].h != ss[i+1].h) break;
if(ss[i].w != ss[i+1].w) break;
}
if(i < 6) flag = false;
//cout << i << " " << flag << endl;;
if(flag)
{
if(ss[0].w != ss[2].w) flag = false;
if(ss[0].h != ss[4].w) flag = false;
if(ss[2].h != ss[4].h) flag = false;
}

if(flag)
puts("POSSIBLE");
else
puts("IMPOSSIBLE");
}
return 0;
}

UVa 1588 Kickdown【模拟】

题目大意:

将两个长度分别为n1,n2且列高只为1或2的长条放入一个高度为3的容器中,问能容纳它们的最短容器长度。

解题思路:

n1、n2长度不超过100,直接做。

这里要注意,不一定是短的连接在后面,也有可能是长的和短的去匹配,看代码最后的样例。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1111;

char s1[N], s2[N];
int a1[N], a2[N], res1, res2, len1, len2;

bool judge(int st)
{
for(int i = st, j = 0; j < len1; ++i, ++j)
{
if(a2[i] + a1[j] == 4)
return false;
}
return true;
}

bool judge2(int st)
{
for(int i = st, j = 0; j < len2; ++i, ++j)
{
if(a1[i] + a2[j] == 4)
return false;
}
return true;
}
int main()
{
while(~scanf("%s%s", s1, s2))
{
res1 = res2 = 0;
len1 = strlen(s1);
len2 = strlen(s2);
memset(a1, 0, sizeof(a1));
memset(a2, 0, sizeof(a2));
for(int i = 0; i < len1; ++i) a1[i] = s1[i] - '0';
for(int i = 0; i < len2; ++i) a2[i] = s2[i] - '0';

// cout << len1 << ' ' << s1 << '\n';
// cout << len2 << ' ' << s2 << '\n';

for(int st = 0; st < len2; ++st)
{
if(judge(st))
{
res1 = max(st + len1, len2);
break;
}
}
if(!res1) res1 = len1 + len2;
for(int st = 0; st < len1; ++st)
{
if(judge2(st))
{
res2 = max(st + len2, len1);
break;
}
}
if(!res2) res2 = len1 + len2;
printf("%d\n", min(res1, res2));
}
return 0;
}
/*
21221
1112212212212211
res = 17
*/

UVa 11809 Floating-Point Numbers【数学】

题目大意:

给你一个浮点数$A \times 10^B$,问当用阶码-尾数的形式表示出来时需要阶码、尾数各多少位。

解题思路:

题目意思就是说,当$A \times 10^B == tm \times 2^{te}$时,$M$和$E$的取值。

其中$tm$为小数部分取$M$个1时表示的最大值,即$1 - \frac{1}{2^{M+1}}$。

$te$为尾数取$E$个1时的最大值,即$2^E-1$。

直接求解,数值太大无法求。

常见的大数转为小数的方法就是取对数,对等式两边进行取对数,得:

$log_{10}A + B == log_{10}tm + log_{10}2 \times te$。

为方便表示,令等式右边的值为$tem$。

因为$0<A<10$ && $B$为整数,所以$B == \lfloor tem \rfloor$,$A == \lfloor tem \rfloor - tem$。还有我们观察到$0 \leq M \leq 9$,$1 \leq E \leq 30$,所以可以预处理出所有答案最后直接查询即可。

最后别忘了浮点数判断相等只要他们大小在某个误差范围内相等就可以。

Mycode:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <sstream>
using namespace std;
const int M = 11;
const int E = 33;
const double eps = 1e-4;

string s;
int b, B[M][E];
double a, A[M][E];
void init()
{
for(int m = 0; m <= 9; ++m)
{
for(int e = 1; e <= 30; ++e)
{
double tm = 1 - 1.0 / (1 << (m + 1));
double te = (1 << e) - 1;
double tem = log10(tm) + log10(2) * te;
B[m][e] = tem;
A[m][e] = pow(10, tem - B[m][e]);
}
}
}
int main()
{
init();
while(cin >> s && s != "0e0")
{
for(int i = 0; i < s.size(); ++i)
if(s[i] == 'e')
s[i] = ' ';
stringstream ss(s);
ss >> a >> b;
for(int m = 0; m <= 9; ++m)
{
for(int e = 1; e <= 30; ++e)
{
if(b == B[m][e] && fabs(a - A[m][e]) < eps)
{
printf("%d %d\n", m, e);
break;
}
}
}
}
return 0;
}
Donate comment here
0%