UVA解题集
来源:互联网 发布:mysql 外键 编辑:程序博客网 时间:2024/06/05 08:07
1 序
系统的整理下第三章的学习笔记。例题代码是在未看书本方法前自己尝试并AC的代码,不一定比书上的标程好;习题除了3-8百度了求解方法,其它均独立完成后,会适当查阅网上资料进行整理总结。希望本博文方便自己日后复习的同时,也能给他人带来点有益的帮助(建议配合紫书——《算法竞赛入门经典(第2版)》阅读本博客)。有不足或错误之处,欢迎读者指出。
2 例题
2.1 UVa272--Tex Quotes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int
main() {
bool logo =
1
;
char
ch;
while
((ch = getchar()) != EOF) {
if
(ch ==
'\"'
) {
if
(logo) printf(
"``"
);
else
printf(
"''"
);
logo ^=
1
;
}
else
putchar(ch);
}
return
0
;
}</stdio.h>
第11行:LRJ的标记变量是用q = !q来实现状态变换,我这里用异或位运算效率更高。
2.2 UVa10082--WERTYU
第一次遇这种题,以为是要用if来暴力做的变态题,然后才发现常量数组的妙用。如果不是小白书看过,真的写不出来。 注意转义字符'\'要写成'\\',下面是第一次AC的代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
char
str[
4
][
50
] = {
"`1234567890-="
,
"QWERTYUIOP[]\\"
,
"ASDFGHJKL;'"
,
"ZXCVBNM,./"
};
int
main() {
int
a[
200
], i, j;
for
(i =
0
; i <
4
; i++)
for
(j =
1
; a[str[i][j]] = str[i][j-
1
]; j++);
a[
' '
] =
' '
; a[
'\t'
] =
'\t'
; a[
'\n'
] =
'\n'
;
while
((i = getchar()) != EOF) putchar(a[i]);
return
0
;
}
</stdio.h>
第11行:这样用getchar循环读入i,对应输出a[i]就行了。
看了白书后,发现自己的办法有些复杂了(虽然效率上高一点)。为什么要分四个子串呢?完全可以合并成一行,然后用一个循环找,找到后输出前一个字符,找不到就原样输出,避免了原代码中第10行的操作。不过我的方法紫书后续也提到了,下面是我综合下优化后的代码:
1
2
3
4
5
6
7
8
9
#include <stdio.h>
char
str[
200
] = {
"`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./ \t\t\n\n"
};
int
main() {
int
a[
200
], i;
for
(i =
1
; a[str[i]] = str[i-
1
]; i++);
while
((i = getchar()) != EOF) putchar(a[i]);
return
0
;
}
</stdio.h>
2.3 UVa401--Palindromes
这题以前小白书做过,写了很久,不够最后的代码还是挺精炼的。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
#include <stdio.h>
#include <string.h>
char
s[
100
], key1[] =
"AEHIJLMOSTUVWXYZ12358"
, key2[] =
"A3HILJMO2TUVMXY51SEZ8"
, *p;
int
ispal()
{
int
i =
0
, j = strlen(s) -
1
;
while
(i < j)
if
(s[i++] != s[j--])
return
0
;
return
1
;
}
int
ismir()
{
int
i = -
1
, j = strlen(s);
while
(++i <= --j)
{
p = strchr(key1, s[i]);
if
(p) {
if
(s[j] != key2[p-key1])
return
0
;}
else
return
0
;
}
return
1
;
}
int
main()
{
int
t;
while
(scanf(
"%s"
, s) != EOF)
{
t = ismir();
printf(
"%s -- is "
, s);
if
(ispal()) printf(
"%s"
, t?
"a mirrored palindrome"
:
"a regular palindrome"
);
else
printf(
"%s"
, t?
"a mirrored string"
:
"not a palindrome"
);
printf(
".\n\n"
);
}
return
0
;
}</string.h></stdio.h>
用两个字符数组存储镜像字符的映射关系。(思想同上题)
没考虑到最中间的字符也要判断是否水平翻转后为其本身,WA几次。(只需略修改循环条件)
学习strchr函数。(该函数找不到字符时返回空指针NULL) LRJ的代码分析:
首先回文串部分LRJ直接在main里判断,我的话没必要为了精简代码而复杂了思维,分成两个子函数不易出错。我的看似短,但总体思路更易于理解。
我是用指针来对应到左右两端,往中间移。LRJ是用下标索引,左是i,右边自然是len-1-i,两种方法都行。
至于他的r函数,正是利用了题目说没有空白输入的特性,写了那个rev字符串,然后将字符直接反转比较。因为字符串肯定没有空格,而反转后非法的字符,在LRJ代码里就变成空格了,肯定匹配不了,所以能巧妙的解决问题!
2.4 UVa340--Master-Mind Hints
这题小白书也做过,因为数字只有1~9,只要统计每个数字出现的次数,减去强匹配的数量就行。思路同书本但没有那么精简,就不贴代码了。2.5 UVa1583--Digit Generator
思路与书本一样。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int
y[
100100
];
int
main() {
for
(
int
i =
0
; i <
100000
; i++) {
int
s = i, t = i;
while
(t) { s+=t%
10
; t/=
10
;}
if
(y[s] ==
0
) y[s] = i;
}
int
T, pos;
scanf(
"%d"
, &T);
while
(T--) {
scanf(
"%d"
, &pos);
printf(
"%d\n"
, y[pos]);
}
return
0
;
}</stdio.h>
2.6 UVa1584--Circular Sequence
题目:输入一个长度在2~100的字符串,要理解成环状,然后能从任意地方作为起点生成一个新的同长度字符串,问这些字符串中字典序最小的是哪个。 分析与求解:字符串的比较可以使用strcmp函数,将要比较的两个字符串首地址,即指针传入即可。那么,我们可以用一个min_p的值来存储当前字典序最小的字符串起始下标,用i来遍历1~len-1的起始下标,因为是环状,所以每轮i循环,都在字符串y末尾添加对应的字符,并添加'\0'方便strcmp的调用。方法跟紫书不一样。具体思路和细节,与strcmp的灵活使用,读者可以自己分析思考。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>
int
main() {
int
T;
scanf(
"%d"
, &T);
while
(T--) {
char
y[
300
];
scanf(
"%s"
, y);
int
len = strlen(y), i, min_p =
0
;
for
(i =
0
; i < len; i++) {
y[i+len] = y[i];
y[i+len+
1
] =
0
;
if
(strcmp(y+min_p,y+i+
1
) >
0
)
min_p = i+
1
;
}
y[min_p+len] =
0
;
printf(
"%s\n"
, y+min_p);
}
return
0
;
}</string.h></stdio.h>
3 习题
3.1 UVa1585--Score
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
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
;
}</stdio.h>
看了这段代码:http://blog.csdn.net/sinat_17231979/article/details/36869231后,发现还是想复杂了,没必要用前n项和公式,直接用一个变量记录当前有多少个O就行了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
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
;
}</stdio.h>
3.2 UVa1586--Molar Mass
暴力每一位i,如果i+1位是数字,判断i+2位是不是数字,分情况计算数量;如果i+1位不是数字,那么数量就是默认的1。接着判断第i位是不是字母,不是则continue,否则累加相应的质量。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
#include <stdio.h>
#include <ctype.h>
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
;
}</ctype.h></stdio.h>
3.3 UVa1225--Digit Counting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
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
;
}</stdio.h>
3.4 UVa455--Periodic Strings
算一个字符串的周期,其周期一定是长度的约数,按这一点枚举,并写一个判断T是不是一个字符串的周期的函数(isThePeriod)即可。输入格式略坑,每两组测试间会有一个空行,所以我用第19行那样的方式解决。
最后注意输出格式,也要每两个隔一个空行~~~
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 <stdio.h>
#include <string.h>
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
;
}</string.h></stdio.h>
3.5 UVa227--Puzzle
这题稍微有些麻烦了,模拟操作,我尽量进行了些优化,而且为了方便交换变量,用了C++里algorithm的swap,没有自己写交换函数。【基本框架】将5*5网格定义为全局变量s(从1开始编号),当前空格所在行列为x,youtput函数用来输出s的矩阵形式ok用来操作一个命令为ch的移动,返回值1代表操作成功,返回0代表失败。成功的话,要更新相应的x、y和进行交换操作swaptest用来完成每组测试的操作总结:对于复杂的问题,要想清思路,然后把大问题划分成一个个小的子问题去求解。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
#include <cstdio>
#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
;
}</algorithm></cstdio>
3.6 UVa232--Crossword Answers
这题就是像中学英语填单词的那种网格。需要对起始点编号,然后按行输出、再按列输出所有单词。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
#include <stdio.h>
#include <string.h>
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
;
}</string.h></stdio.h>
3.7 UVa1368--DNA Consensus
思路:找出每列中ACGT出现次数最多的字符,就是最优解序列在这一列的字符值。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 <stdio.h>
#include <string.h>
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
;
}</string.h></stdio.h>
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...
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
#include <stdio.h>
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);
}
}</stdio.h>
3.9 UVa10340--All in All
遍历后者,找前者往后是否有对应的字符。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <string>
#include <iostream>
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"
;
}
}</iostream></string>
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 #include using 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函数)只要巧妙的利用对称性,就能重复利用上一段的代码了。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
#include <stdio.h>
#include <string.h>
#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
;
}</algorithm></string.h></stdio.h>
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就能解决了。
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 <math.h>
#include <stdio.h>
#include <string.h>
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
;
}</string.h></stdio.h></math.h>
转载网址:http://www.2cto.com/kf/201408/322120.html
0 0
- UVA解题集
- {UVA} UVA-414 解题报告
- {UVA} UVA-490 解题报告
- {UVA}UVA-489解题报告
- 解题 UVA 424
- 解题 UVA 10035
- 解题 UVA 10081 Undone
- UVA 10878 解题报告
- UVA 10815 解题报告
- UVA 10010 解题报告
- UVA 10115 解题报告
- UVA 10361 解题报告
- UVA 537 解题报告
- UVA 409 解题报告
- UVA 644 解题报告
- UVA 10494 解题报告
- UVA 424 解题报告
- UVA 10106 解题报告
- oracle中数据格式
- c#中的'&'和'&&','|'和'||'
- linux命令整理
- MySQL联表查询
- 3DTouch为你的app添加类似微信的快捷弹出按钮
- UVA解题集
- lua与c++交互(基础篇)
- swift 中的数组
- 如何连接免费VPN
- 解决git提交时提示“git did not exit cleanly (exit code 1)” 问题
- Kubernetes基础概念
- 不同VLAN之间相互通信的两种方式 (单臂路由、三层交换)
- Android.V4的ViewPager的源码和改造(一)
- HttpClient Cookies设置