UVa 11663 - GrayInc

Problem

Gray Inc. is a software fabricant specialized in management of Gray codes. An n-binary code, for n $\geq$ 1, is a sequence of words w0, w1,… that includes every possible binary word of n bits. An n-Gray code is an n-binary code such that between any two consecutive words there is only one bit that changes, i.e., they differ at exactly one position. As you might be aware by now, there are many n-Gray codes.

Gray Inc. produces its own particular kind of Gray code in the following way (name Gn the produced n-Gray code, n $\geq$ 1):

$$Gn = \left\{\vphantom{ \begin{array}{lr} \langle 0 , 1 \rangle & \... ... (0G_{n-1}) \, (1G_{n-1}^R) & \textrm{if } n \geq 2 \\ \end{array} }\right. \begin{array}{lr} \langle 0 , 1 \rangle & \textrm{if } n = 1\\ & \\ (0G_{n-1}) \, (1G_{n-1}^R) & \textrm{if } n \geq 2 \\ \end{array}$$

The notation defining Gn should be understood as follows:

$bA$ : appends bit b to every element of the sequence A;
$AB$ : concatenates sequences A and B;
$A^{R}$ : sequence with the elements of sequence A in reversed order.

For instance,

G2 = (0G1) (1G1R)
= (0$\displaystyle \langle$0, 1$\displaystyle \rangle$) (1$\displaystyle \langle$0, 1$\displaystyle \rangle^_{}$)
= (0$\displaystyle \langle$0, 1$\displaystyle \rangle$) (1$\displaystyle \langle$1, 0$\displaystyle \rangle$)
= $\displaystyle \langle$00, 01$\displaystyle \rangle$$\displaystyle \langle$11, 10$\displaystyle \rangle$
=    {% math %}\displaystyle \langle{% endmath %}00, 01, 11, 10{% math %}\displaystyle \rangle{% endmath %}

and

G3 = (0G2) (1G2R)
= (0$\displaystyle \langle$00, 01, 11, 10$\displaystyle \rangle$) (1$\displaystyle \langle$00, 01, 11, 10$\displaystyle \rangle^_{}$)
= (0$\displaystyle \langle$00, 01, 11, 10$\displaystyle \rangle$) (1$\displaystyle \langle$10, 11, 01, 00$\displaystyle \rangle$)
= $\displaystyle \langle$000, 001, 011, 010$\displaystyle \rangle$$\displaystyle \langle$110, 111, 101, 100$\displaystyle \rangle$
= $\displaystyle \langle$000, 001, 011, 010, 110, 111, 101, 100$\displaystyle \rangle$

Observe that not only Gn is an n-Gray code, but also a circular Gray code as the first word in the sequence may be regarded as the successor of the last one in the sequence.

Gray Inc. wants your help to solve the following problem: given a binary word w in Gn and a natural number m, they want to produce the binary word in the sequence Gn that is m words ahead w in the listing (of course, considering the circular ordering described above). Can you help them?

Input

The problem input consists of several cases, each one defined by a line with an integer m ( 0 < m $\leq$ 1000), and a binary n-word w ( 1 $\leq$ n $\leq$ 100), separated by one blank.

The end of the input is given by a line with m = 0 and w = 0.

Output

For each input case, your solution should output the n-binary word that is m words ahead of w in the listing of Gn.

Sample Input

1
2
3
4
5
6
7
1 0
3 0
1 1
1 11
6 011
123 010101010
0 0

Sample Output

1
2
3
4
5
6
1
1
0
10
000
111100100

Solution

題目描述:

根據格雷碼的產生方式,找到某個格雷碼的下 m (m < 1000) 個格雷碼為何。

題目解法:

由於給定的格雷碼長度可能太長,因此如果要用數學解的話必須搭配大數處理,然而 m 就相對於小,因此直接使用原本的格雷碼窮舉方式,針對給定的格雷碼進行還原操作,還原結束後,開始計數直到指定的格雷碼。

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
#include <stdio.h>
#include <string.h>
//#define DEBUG
int gray(int n, int k) { // find k-th gray code
if(n == 0) return 0;
if(k >= (1<<(n-1)))
return (1<<(n-1)) | gray(n-1, (1<<(n))-k-1);
else
return gray(n-1, k);
}
int path[128];
void grayNext(int idx, int n, char w[], int& k, int &f) {
if(f == 2) return;
if(idx == n) {
if(f == 0) {
f = 1;
} else {
k--;
if(k == 0) {
for(int i = 0; i < n; i++)
printf("%d", path[i]);
puts("");
f = 2;
}
}
#ifdef DEBUG
for(int i = 0; i < n; i++)
printf("%d", path[i]);
puts("");
#endif
return ;
}
if(f == 0) {
if(w[idx] == path[idx] + '0') {
grayNext(idx+1, n, w, k, f);
path[idx] = !path[idx];
grayNext(idx+1, n, w, k, f);
} else {
for(int i = idx; i < n; i++)
path[i] = 0;
path[idx] = w[idx] - '0';path[idx+1] = 1;
grayNext(idx+1, n, w, k, f);
}
} else {
grayNext(idx+1, n, w, k, f);
path[idx] = !path[idx];
grayNext(idx+1, n, w, k, f);
}
}
int main() {
int n, m, f;
char w[1024];
while(scanf("%d %s", &n, w) == 2 && n) {
f = 0;
memset(path, 0, sizeof(path));
m = strlen(w);
// printf("find next %d\n", n);
grayNext(0, m, w, n, f);
while(n) {
memset(path, 0, sizeof(path));
grayNext(0, m, w, n, f);
}
}
return 0;
}
Read More +

UVa 11633 - Food portion sizes

Problem

The university canteen does not want any student to leave the canteen hungry. Therefore, as long as a student is hungry, he can get another portion of food for free. The canteen uses a fixed food portion size, because it would take too much time to first ask a student how much food he wanted. It can happen that a student doesn’t finish his last portion of food and the remainder has to be thrown away.

To minimize costs, the manager of the canteen wants to determine a food portion size S such that the amount of food that is wasted is small, but also the number of times the students have to fetch another portion of food is not too big. Note that these two goals can be conflicting:

  • By choosing a very small food portion size, one does not waste food, but simultaneously the number of times the students have to fetch food is big.
  • By choosing a large food portion size, one can make sure each student has to fetch only one portion, but at the same time it may happen that a large quantity of food is wasted.

The manager of the canteen has collected data about how many units of food each student eats. The problem to be solved can now be formulated mathematically as follows: Let x be the amount of food that is wasted, and y the number of times the students go to fetch food. Then, the goal is to minimize a × x + b × y, where a, b are weights that represent the relative importance of the two opposing goals. Note that x and y depend on the food portion size S and the quantities of food each student eats. We impose the additional constraint that no student should have to go more than 3 times to fetch food.

Input Specification

The input file contains several test cases. Each test case starts with a line containing an integer n, (1 ≤ n ≤ 1000), the number of students eating in the canteen. The next line contains the values a and b (1 ≤ a, b ≤ 10). The third line of each test case consists of n integers y1, …, yn (1 ≤ yi ≤ 100), where yi is the amount of food student i eats. Input is terminated by n=0.
Output Specification

For each test case print one line containing the costs resulting from an optimal choice of the food portion size. Print each value as a reduced fraction. If the result is an integer, do not print the denominator 1. See the sample output for details.

Sample Input

1
2
3
4
5
6
7
8
9
10
5
1 1
3 7 1 9 12
3
10 1
11 13 17
2
2 3
6 3
0

Sample Output

1
2
3
35 / 2
154 / 3
9

Solution

題目描述:

學生餐廳為了不讓學生餓肚子,以及方便他們為每一個學生製作餐點,每一份餐點的量都會相同,然而一份餐點對於某些學生來說太少,因此必須多跑幾次餐廳才能吃飽,已知每位學生不會跑大於 3 次餐廳,而每位學生只會吃自己所需要的份量,剩餘的份量就是浪費。

請最小化 $ax + by$,其中 a, b 為給定的常數,x 為所有學生所製造的廚餘,y 為所有學生跑餐廳次數的總和。

題目解法:

由於可能跑 1, 2, 3 次,通分得到分母為 6,保證最小化一定通過某一個人的其中一種情況,窮舉每一個人跑餐廳的次數後,並且在合法的情況下 (所有人皆不大於 3 次。),計算 $ax + by$ 的結果。

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
#include <stdio.h>
#include <algorithm>
using namespace std;
int main() {
int n, a, b;
int v[1024];
while(scanf("%d", &n) == 1 && n) {
scanf("%d %d", &a, &b);
int mx = 0;
for(int i = 0; i < n; i++) {
scanf("%d", &v[i]);
v[i] *= 6; // v[i]/3, v[i]/2, v[i]/1
mx = max(mx, v[i]);
}
int minCost = 0x3f3f3f3f;
for(int i = 0; i < n; i++) {
for(int j = 1; j <= 3; j++) {
int S = v[i]/j;
int x = 0, y = 0;
if(S * 3 < mx) continue;
for(int k = 0; k < n; k++) {
x += (S * (v[k]/S + (v[k]%S != 0)) - v[k]);
y += v[k]/S + (v[k]%S != 0);
}
if(a * x + 6 * b * y < minCost)
minCost = a * x + 6 * b * y;
}
}
if(minCost%6 == 0)
printf("%d\n", minCost /6);
else {
int div = 6, g = __gcd(minCost, div);
div /= g, minCost /= g;
printf("%d / %d\n", minCost, div);
}
}
return 0;
}
Read More +

UVa 11632 - Elias gamma coding

Problem

The Elias gamma code is a simple code which can be used to encode a sequence of positive integers. We will use a modified code which is also able to encode zeros. To encode an integer n, do the following:

Let k be the number of bits of n
Write k-1 zeros followed by a 1
Write n in binary

Examples

Number     Binary     Number of bits     Prefix     Code
0     0     1     1     10
1     1     1     1     11
2     10     2     01     0110
3     11     2     01     0111
4     100     3     001     001100
5     101     3     001     001101
6     110     3     001     001110
7     111     3     001     001111
8     1000     4     0001     00011000

A sequence of integers is encoded by writing the codes of the individual integers of the sequence in the same order as the integers appear in the sequence. The prefix of k additional bits before the binary representation of each integer is needed to be able to decode the encoded integers. So when reading the encoding of a sequence of integers, if we read k-1 zeros followed by a one, it means that there are k bits following which are the binary representation of the next encoded integer.

If we want to shorten the length of the encoding of a sequence of integers, there may be still some room for improvement; we will consider the following two optimizations:

  • If there is a prefix which indicates that k bits are following, but there is no integer in the sequence with k bits, we can use this prefix to indicate that k+1 bits are following. If there already was a prefix which indicates that k+1 bits are following, this prefix is not needed anymore, and it can be used to indicate that k+2 bits are following, and so on.

  • We can add a leading zero to the binary representation of all integers in the sequence with k bits, which then become integers with k+1 bits, and then the first optimization can be used. This optimization seems especially useful if there are few integers with k bits, but many integers with more than k bits.

When we are minimizing the length of the encoding of a sequence of integers, we only care about how many integers in the sequence have a certain number of bits. Let ci denote the number of integers in a sequence with i bits.

Let us look at the following example: c1 = 2, c2 = 4, c3 = 0, c4 = 1 (which, for example, could correspond to a sequence 2, 1, 3, 8, 0, 2, 3). With the original elias gamma coding, the encoding of the sequence would have length 2 × (1 + 1) + 4 × (2 + 2) + 0 × (3 + 3) + 1 × (4 + 4) = 28. By using optimization 1 we can save 1 bit by using prefix 001 for the integer with 4 bits. Then, we could use optimization 2 and add leading zeros to the integers with 1 bit, making them use 2 bits. Then, we use optimization 1 and use prefix 1 for the integers with 2 bits, prefix 01 for the integer with 4 bits, and we get the new length of 6 × (1 + 2) + 1 × (2 + 4) = 24.

Both optimizations can possibly be used several times. Note that for the second optimization, it is not easy to decide when and how to use it. The goal is to combine these two optimizations in the best possible way, that means we want to find an encoding of a given sequence of integers that has minimum length among all encodings using elias gamma coding with any combination of these two optimizations.

Input Specification

The input file contains several test cases. Each test case starts with a line containing an integer n, (1 ≤ n ≤ 128). The next line contains the values c1, …, cn (0 ≤ ci ≤ 10000). Input is terminated by n=0.
Output Specification

For each test case print one line with the minimum length of an encoding of the given input sequence.

Sample Input

1
2
3
4
5
6
7
4
2 4 0 1
5
9 4 2 4 3
11
44 56 96 26 73 80 77 50 33 16 78
0

Sample Output

1
2
3
24
99
5494

Solution

題目描述:

對於一個編碼而言,假使全部存放數字,採用固定長度的方式儲存,就類似全部使用 32 bit 形式,但這樣會浪費相當多的首位 0,因此題目給定多一個欄位表示接下來會有多少 bits,這樣方式有可能會增加編碼長度,因此會有以下優化。

  • 將一個原本使用 k bits 表示的數字,使用多於 k bits 表示,也就是多補給個 0。
  • 對於欄位表示,將使用映射的方式進行,由於前一條規則,將會有無用的欄位格式,因此可以將比較短的表示法給更多 bits 的數字使用。

題目解法:

題目相當冗長,其實就相當於將 3 bit 數字弄成 4 bit,並且讓 3 bits 和 4 bits 共用同一種欄位表示法 (001 之類的,原本 4 bit 必須使用 0001,現在反而能用更少。)。

使用 dp[i][j] 表示前 i bits 表示法使用最大 j bits 欄位的最小成本。

1
2
dp[j][k] = min(dp[j][k], dp[i-1][k-1] + sum * (k + j));
// sum 表示 [i, j] 之間的 bits 數字總量,k + j 表示單一數字的表示長度。
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 <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int main() {
int n, A[256];
while(scanf("%d", &n) == 1 && n) {
for(int i = 1; i <= n; i++)
scanf("%d", &A[i]);
int dp[256][256];
memset(dp, 63, sizeof(dp));
dp[0][0] = 0;
for(int i = 1; i <= n; i++) {
int sum = 0;
for(int j = i; j <= n; j++) {
sum += A[j];
for(int k = 1; k <= n; k++) {
dp[j][k] = min(dp[j][k], dp[i-1][k-1] + sum * (k + j));
}
}
}
int ret = 0x3f3f3f3f;
for(int i = 0; i <= n; i++)
ret = min(ret, dp[n][i]);
printf("%d\n", ret);
}
return 0;
}
Read More +

UVa 11613 - Acme Corporation

Problem

Wile E. Coyote is back. He is back in the business. The business of capturing the road runner. Being the most loyal customer to the Acme Corporation, they are hoping to do some great business with him. Although, Acme makes literally every kinds of devices, all of them has a similarity, that has been kept secret for ages. All of their products use a secret element “element X” (this is kept so secret that, only you and the Acme people know about this). The decision makers of the Acme Corp. has already estimated the maximum amount of element X that can be used into manufacture every month.

For month i, the per unit manufacturing cost of “element X” is mi, and at most ni units can be produced. Moreover, the selling price for “element X” for that month is pi. One more thing is that, element X older than Ei months can not be used. But good thing is that, they can store any amount of element X in their inventory (it’s the Acme Corp, they can make anything :) ). Now, Acme Corporation wants to know how much element X should be produced and sold, to make the highest amount of profit.

Input

l First line contains T, the number of test cases.

l For each test case

u First line contains two integers M and I, the number of months to consider and the cost of storing per unit of element X per month in the inventory.

u Each of the next M lines describe the parameters for each month

· The ith line contains 5 integers, mi, ni, pi, si, Ei, where mi is the per unit manufacturing cost for month i, ni is the maximum amount that can be manufactured in this month, pi is the selling price for that month(per unit), si is the maximum amount that can be sold that month, and Ei is the maximum time,element X manufactured on month i, can be stored in the inventory. For example, if for month 1, E1 = 3, the elements produced in month 1 can be sold in months 1, 2, 3 and 4. But it can not be sold in month 5.

Output

For each test case, output the case number and the maximum amount of profit, Acme Corporation can make. Note that, you have to think of only M months. If any amount of element X is stored in the inventory after this period, are completely ignored. For formatting, see the sample input and output.

Sample Input

1
2
3
4
1
2 2
2 10 3 20 2
10 100 7 5 2

Output for Sample Input

1
Case 1: 20

Solution

題目描述:

這個工廠,每個月會生產商品,在每個月中,每一個商品會有其生產成本、該月最大生產量、該月最大銷售量、產品的保存期限。

然而沒有銷售的的商品,將會放置於倉庫,每個月的保管成本為 I。求最大獲益金額為何。

題目解法:

將銷售金額與負號,最小費用流即最大獲益。

source - product - sell - sink,將每一個月的訊息拆成兩個節點,生產的數量和銷售的情況,並且根據保存期限,將該月的生產數量拉至可預期的銷售時間,並且同時扣除保管成本。

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
#include <stdio.h>
#include <string.h>
#include <queue>
#include <deque>
using namespace std;
struct Node {
int x, y;
long long cap, cost;// x->y, v
int next;
} edge[262144];
int e, head[512], prev[512], record[512], inq[512];
long long dis[512];
void addEdge(int x, int y, long long cap, long long cost) {
edge[e].x = x, edge[e].y = y, edge[e].cap = cap, edge[e].cost = cost;
edge[e].next = head[x], head[x] = e++;
edge[e].x = y, edge[e].y = x, edge[e].cap = 0, edge[e].cost = -cost;
edge[e].next = head[y], head[y] = e++;
}
long long mincost(int s, int t) {
long long mncost = 0, flow, totflow = 0;
int i, x, y;
while(1) {
memset(dis, 63, sizeof(dis));
int oo = dis[0];
dis[s] = 0;
deque<int> Q;
Q.push_front(s);
while(!Q.empty()) {
x = Q.front(), Q.pop_front();
inq[x] = 0;
for(i = head[x]; i != -1; i = edge[i].next) {
y = edge[i].y;
if(edge[i].cap > 0 && dis[y] > dis[x] + edge[i].cost) {
dis[y] = dis[x] + edge[i].cost;
prev[y] = x, record[y] = i;
if(inq[y] == 0) {
inq[y] = 1;
if(Q.size() && dis[Q.front()] > dis[y])
Q.push_front(y);
else
Q.push_back(y);
}
}
}
}
if(dis[t] > 0) break;
flow = oo;
for(x = t; x != s; x = prev[x]) {
int ri = record[x];
flow = min(flow, edge[ri].cap);
}
for(x = t; x != s; x = prev[x]) {
int ri = record[x];
edge[ri].cap -= flow;
edge[ri^1].cap += flow;
edge[ri^1].cost = -edge[ri].cost;
}
totflow += flow;
mncost += dis[t] * flow;
}
return mncost;
}
int main() {
int testcase, cases = 0;
int M, I;
int pm[128], pn[128], pp[128], ps[128], pe[128];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d", &M, &I);
e = 0;
memset(head, -1, sizeof(head));
int source = 2 * M + 2, sink = source + 1;
for(int i = 1; i <= M; i++)
scanf("%d %d %d %d %d", pm+i, pn+i, pp+i, ps+i, pe+i);
#define INF 0x3f3f3f3f
for(int i = 1; i <= M; i++) {
addEdge(source, 2*i, pn[i], pm[i]);
for(int j = i; j <= min(i + pe[i], M); j++)
addEdge(2*i, 2*j+1, INF, (j - i) * I);
addEdge(2*i+1, sink, ps[i], -pp[i]);
}
printf("Case %d: %lld\n", ++cases, -mincost(source, sink));
}
return 0;
}
Read More +

UVa 11605 - Lights inside a 3d Grid

You are given a 3D grid, which have dimensions N, M and P. Each of the M x N x P cells has a light. Initially all lights are off. You will have K turns. In each of the K turns,

  • You will select a cell A randomly from the grid

  • You will select a cell B randomly from the grid

  • Toggle the states of all the bulbs bounded by cell A and cell B, ie make all the ON lights OFF and make all the OFF lights ON which are bounded by A and B. To be more clear, consider cell A is (x1, y1, z1) and cell B is (x2, y2, z2). Then you have to toggle all the bulbs in grid cell (x, y, z) where min(x1,x2)<=x<=max(x1,x2) , min(y1,y2)<=y<=max(y1,y2) and min(z1, z2)<=z<=max(z1, z2).

How many bulbs are expected to be ON after K turns?

Note:

  • A and B can be the same cell.

Input

First line of the input is an integer T(T<101) which denotes the number of test cases. Each of the next T lines represents one test case by 4 integers N, M, P (0 < M, N, P < 101) and K (0<=K<=10000) separated by spaces.

Output

Output one line for each test cases giving the expected number of ON lights. Up to 1E-6 error in your output will be acceptable. Print the case number followed by the output. Look at the sample output for exact format.

Sample Input

1
2
3
2
2 3 4 1
2 3 4 2

Output for Sample Input

1
2
Case 1: 6.3750000000
Case 2: 9.0976562500

Solution

題目描述:

在 N x M x P 的三維空間中,任抓 2 個格子所構成的長方體,將長方體內部的所有格子點進行反轉標記 (一開始全是 OFF),抓取 K 次得到的 ON 標記格子數期望值為何?

題目解法:

每一個軸的情況可以分開考慮,考慮對於座標 (x, y, z) 被選到的機率 p,則 sigma(p * 1) = 所求的期望值。

1
2
p = dp[N][x] * dp[M][y] * dp[P][z],
dp[i][j] 表示在區間 [1, i] 中任挑區間包含 j 的機率為何。

得到 p 之後,計算在 K 次中,得到奇數 ON 的機率為何,這裡藉由矩陣乘法來完成。

1
2
3
4
[1 - p, p]
[p, 1 - p] = M
[0 ON] [final ON p]
M ^ K * [1 OFF] = [final OFF p]

藉由快速取冪次來完成。

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
#include <stdio.h>
#include <string.h>
struct Matrix {
double v[2][2];
int row, col; // row x col
Matrix(int n, int m, double a = 0) {
memset(v, 0, sizeof(v));
row = n, col = m;
for(int i = 0; i < row && i < col; i++)
v[i][i] = a;
}
Matrix operator*(const Matrix& x) const {
Matrix ret(row, x.col);
for(int i = 0; i < row; i++)
for(int j = 0; j < x.col; j++)
for(int k = 0; k < col; k++)
ret.v[i][j] += v[i][k] * x.v[k][j];
return ret;
}
Matrix operator^(const int& n) const {
Matrix ret(row, col, 1), x = *this;
int y = n;
while(y) {
if(y&1) ret = ret * x;
y = y>>1, x = x * x;
}
return ret;
}
};
int main() {
int N, M, P, K;
int testcase, cases = 0;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d %d %d", &N, &M, &P, &K);
double pN[128], pM[128], pP[128];
for(int i = 1; i <= N; i++)
pN[i] = (i * (N-i+1) * 2 - 1) / (double)(N * N);
for(int i = 1; i <= M; i++)
pM[i] = (i * (M-i+1) * 2 - 1) / (double)(M * M);
for(int i = 1; i <= P; i++)
pP[i] = (i * (P-i+1) * 2 - 1) / (double)(P * P);
double ret = 0;
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= M; j++) {
for(int k = 1; k <= P; k++) {
double p = pN[i] * pM[j] * pP[k];
Matrix mm(2, 2);
mm.v[0][0] = mm.v[1][1] = 1 - p;
mm.v[0][1] = mm.v[1][0] = p;
Matrix mmk = mm ^ K;
ret += mmk.v[0][1];
}
}
}
printf("Case %d: %.10lf\n", ++cases, ret);
}
return 0;
}
Read More +

UVa 11603 - Its all about the Bandwidth

Problem

My appartment has n computers. My friend’s appartment also has n computers. In each appartment, some pairs of computers are connected to each other with AcidNet cables (ignoring the routers). Each connection has a certain bandwidth (in bytes per second). My friend always brags about the speed of his computer network. He always shows me his n-by-n table that lists the bandwidths between each pair of computers. My network is slower, and I want to rebuild it. So I want to know how I should connect my computers in order to have the same n-by-n bandwidth table.

Since I don’t want to buy too many AcidNet cables, you’ll need to find a solution with the minimum number of connections. You may use AcidNet cables of any integer bandwidth - they all have the same price at my local Imaginary Hardware Store.
Problem, in short

Given a graph, you can compute the all-pairs maximum flow table, right? Now do the opposite: given an n-by-n symmetric table, find a graph with fewest edges that has the given table of all-pairs maximum flows.

Input

The first line of input gives the number of cases, N. N test cases follow. Each one is a line containing n (0 < n ≤ 200), followed by n lines with n integers each, giving the table T.

T[u][u] will always be 0.
T[u][v] will always be positive and equal to T[v][u].
T[i][j] ≤ 10000

T[u][v] is the largest possible speed (in bytes per second) for sending information from computer u to computer v, assuming there is no other traffic on the network.

Output

For each test case, output one line containing “Case #x:” followed by m - the number of cables I have to buy. The next m lines will each contain 3 integers u, v and w meaning that I need to connect computer u to computer v using an AcidNet cable of bandwidth w. Computers are numbered starting at 0.

If there is no solution, print Impossible.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4
2
0 10
10 0
3
0 1 1
1 0 2
1 2 0
1
0
4
0 2 2 1
2 0 2 2
2 2 0 2
1 2 2 0

Output for Sample Input

1
2
3
4
5
6
7
Case #1: 1
0 1 10
Case #2: 2
0 1 1
1 2 2
Case #3: 0
Case #4: Impossible

Solution

題目描述:

朋友給一個他的端點之間的頻寬關係,這些頻寬關係是對稱的,現在要用最少條的邊做出跟朋友一樣的網路頻寬關係,請問是否有可能,如果可能的話,請輸出需要擺設的邊。

題目解法:

假設有 n 個節點,要用最少條構成,相當於給定一個 n - 1 條邊的 tree,對於一個 tree 而言,彼此之間的流量關係符合不等式

$cap(i, j) \le min(cap(i, k), cap(k, j))$

也就是說,如果存在更好的流量方式,則會在關係圖中表示出來。在判斷是否可能即檢查所有情況是否符合不等式。最後根據這條不等式,相當於最小生成樹中 s - t 集合中的關係。

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
#include <stdio.h>
#include <algorithm>
using namespace std;
struct E {
int x, y, v;
E(int a = 0, int b = 0, int c = 0):
x(a), y(b), v(c) {}
bool operator<(const E &a) const {
return v > a.v;
}
};
E D[65536];
int p[256], rank[256];
int findp(int x) {
return p[x] == x ? x : (p[x]=findp(p[x]));
}
int joint(int x, int y) {
x = findp(x), y = findp(y);
if(x == y) return 0;
if(rank[x] > rank[y])
rank[x] += rank[y], p[y] = x;
else
rank[y] += rank[x], p[x] = y;
return 1;
}
int main() {
int testcase, cases = 0, n, g[256][256];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &n);
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
scanf("%d", &g[i][j]);
printf("Case #%d: ", ++cases);
int eflag = 0;
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
for(int k = j+1; k < n; k++)
if(min(g[i][j], g[j][k]) > g[i][k] ||
min(g[i][k], g[j][k]) > g[i][j] ||
min(g[i][j], g[i][k]) > g[j][k])
eflag = 1, i = j = k = n;
if(eflag) {
puts("Impossible");
continue;
}
printf("%d\n", n - 1);
int m = 0;
for(int i = 0; i < n; i++)
p[i] = i, rank[i] = 1;
for(int i = 0; i < n; i++)
for(int j = i+1; j < n; j++)
D[m++] = E(i, j, g[i][j]);
sort(D, D+m);
for(int i = 0; i < m; i++) {
if(joint(D[i].x, D[i].y)) {
printf("%d %d %d\n", D[i].x, D[i].y, D[i].v);
}
}
}
return 0;
}
Read More +

UVa 1592 - Database

Problem

Peter studies the theory of relational databases. Table in the relational database consists of values that are arranged in rows and columns.

There are different normal forms that database may adhere to. Normal forms are designed to minimize the redundancy of data in the database. For example, a database table for a library might have a row for each book and columns for book name, book author, and author’s email.

If the same author wrote several books, then this representation is clearly redundant. To formally define this kind of redundancy Peter has introduced his own normal form. A table is in Peter’s Normal Form (PNF) if and only if there is no pair of rows and a pair of columns such that the values in the corresponding columns are the same for both rows.

How to compete in ACM ICPC     Peter     peter@neerc.ifmo.ru
How to win ACM ICPC     Michael     michael@neerc.ifmo.ru
Notes from ACM ICPC champion     Michael     michael@neerc.ifmo.ru

The above table is clearly not in PNF, since values for 2rd and 3rd columns repeat in 2nd and 3rd rows. However, if we introduce unique author identifier and split this table into two tables – one containing book name and author id, and the other containing book id, author name, and author email, then both resulting tables will be in PNF.

$$\begin{center} \begin{tabular}{\vert l\vert l... ...\hline Notes from ACM ICPC champion & 2 \\ \hline \end{tabular} \end{center}} \begin{center} \begin{tabular}{\vert l\vert ... ...ine 2 & Michael & michael@neerc.ifmo.ru \\ \hline \end{tabular} \end{center}}$$

Given a table your task is to figure out whether it is in PNF or not.

Input

Input contains several datasets. The first line of each dataset contains two integer numbers n and m ( 1$\le$n$\le$10000, 1$\le$m$\le$10), the number of rows and columns in the table. The following n lines contain table rows. Each row has m column values separated by commas. Column values consist of ASCII characters from space (ASCII code 32) to tilde (ASCII code 126) with the exception of comma (ASCII code 44). Values are not empty and have no leading and trailing spaces. Each row has at most 80 characters (including separating commas).

Output

For each dataset, if the table is in PNF write to the output file a single word YES" (without quotes). If the table is not in PNF, then write three lines. On the first line write a single wordNO” (without quotes). On the second line write two integer row numbers r1 and r2 ( 1$\le$r1, r2$\le$n, r1$\ne$r2), on the third line write two integer column numbers c1 and c2 ( 1$\le$c1, c2$\le$m, c1$\ne$c2), so that values in columns c1 and c2 are the same in rows r1 and r2.

Sample Input

1
2
3
4
5
6
7
3 3
How to compete in ACM ICPC,Peter,peter@neerc.ifmo.ru
How to win ACM ICPC,Michael,michael@neerc.ifmo.ru
Notes from ACM ICPC champion,Michael,michael@neerc.ifmo.ru
2 3
1,Peter,peter@neerc.ifmo.ru
2,Michael,michael@neerc.ifmo.ru

Sample Output

1
2
3
4
NO
2 3
2 3
YES

Solution

題目描述:

這一題要做的是資料庫的正規化,在一個表單中,重複關係的項目都要依序剃除。
而這一條講的就是要檢查是否有某兩行中的某兩列數值相同,換句話說就是

(data(r1, c1), data(r1, c2)) === (data(r2, c1), data(r2, c2))

如果存在則輸出任何一組 r1, r2, c1, c2

題目解法:

窮舉行還是列將決定複雜度。如果窮舉行 (row) 則會達到 O(n ^ 2 m log m) 反之則是 O(m ^ 2 n log n)

由於題目給定的 n 遠大於 m,因此窮舉列 (column) 會來得更好。為了加速字串比對速度,可以利用 hash 來完成,如果 hash 夠大,將有機會不考慮任何字串匹配 (不會發生碰撞),這樣的速度就會非常快。

拿了不少 WA 是忘記在找到其中一組解 break; 掉。Orz

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
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
char data[10010][128];
int colPos[10010][16];
int hashCode[10010][16];
struct cmp {
static int C1, C2;
bool operator() (const pair< pair<int, int>, int>& a,
const pair< pair<int, int>, int>& b) const {
if(a.first != b.first) return a.first < b.first;
int t;
t = strcmp(data[a.second] + colPos[a.second][C1],
data[b.second] + colPos[b.second][C1]);
if(t) return t < 0;
t = strcmp(data[a.second] + colPos[a.second][C2],
data[b.second] + colPos[b.second][C2]);
if(t) return t < 0;
return false;
}
};
int cmp::C1 = 0;
int cmp::C2 = 0;
int main() {
int n, m;
// freopen("in.txt", "r+t", stdin);
// freopen("out.txt", "w+t", stdout);
while(scanf("%d %d", &n, &m) == 2) {
while(getchar() != '\n');
for(int i = 0; i < n; i++) {
gets(data[i]);
for(int j = 0, pos = 0; j < m; j++) {
colPos[i][j] = pos;
int hash = 0;
while(data[i][pos] != ',' && data[i][pos] != '\0')
hash = ((hash<<15) + data[i][pos])&32767, pos++;
hashCode[i][j] = hash;
data[i][pos] = '\0', pos++;
}
}
pair< pair<int, int>, int> D[10010];
int flag = 0, r1, r2, c1, c2;
for(int i = 0; i < m; i++) {
for(int j = i + 1; j < m; j++) {
for(int k = 0; k < n; k++) { // (hashCode[k][i], hashCode[k][j])
D[k] = make_pair(make_pair(hashCode[k][i], hashCode[k][j]), k);
}
cmp::C1 = i, cmp::C2 = j;
sort(D, D + n, cmp());
for(int k = 1; k < n; k++) {
if(!cmp()(D[k], D[k-1]) && !cmp()(D[k-1], D[k])) {
flag = 1;
r1 = D[k-1].second, r2 = D[k].second;
c1 = i, c2 = j;
i = j = m;
break;
}
}
}
}
puts(flag ? "NO" : "YES");
if(flag)
printf("%d %d\n%d %d\n", r1 + 1, r2 + 1, c1 + 1, c2 + 1);
}
return 0;
}
Read More +

UVa 11542 - Square

Given n integers you can generate $2^{n} - 1$ non-empty subsets from them. Determine for how many of these subsets the product of all the integers in that is a perfect square. For example for the set {4,6,10,15} there are 3 such subsets. {4}, {6,10,15} and {4,6,10,15}. A perfect square is an integer whose square root is an integer. For example 1, 4, 9, 16,…. .

Input

Input contains multiple test cases. First line of the input contains T(1≤T≤30) the number of test cases. Each test case consists of 2 lines. First line contains n(1≤n≤100) and second line contains n space separated integers. All these integers are between 1 and 10^15. None of these integers is divisible by a prime greater than 500.

Output

For each test case output is a single line containing one integer denoting the number of non-empty subsets whose integer product is a perfect square. The input will be such that the result will always fit into signed 64 bit integer.

Sample Input

1
2
3
4
5
6
7
8
9
4
3
2 3 5
3
6 10 15
4
4 6 10 15
3
2 2 2

Output for Sample Input

1
2
3
4
0
1
3
3

Solution

題目描述:

將 N 個數字,任挑相乘為平方數的方法數有多少?

題目解法:

將每個數字做質因數分解,對於每個質數將會有一條方程式,其參數為能貢獻的質因數的個數。

x1 = 0 表示第一個數字如果不選,x1 = 1 則表示選。

因此,最後希望所有方程式加總都必須要是偶數。

$$a_{1}x_{1} + a_{2}x_{2} + ... = even \quad for \quad prime \quad 2 \\ b_{1}x_{1} + b_{2}x_{2} + ... = even \quad for \quad prime \quad 3 \\ ...$$

使用 XOR 高斯消去法,找到任意解的變數個數 (大陸: 自由基) 即能得到所有解個數大小。

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
#include <stdio.h>
#include <algorithm>
using namespace std;
#define maxL (500>>5)+1
#define GET(x) (mark[x>>5]>>(x&31)&1)
#define SET(x) (mark[x>>5] |= 1<<(x&31))
int mark[maxL];
int P[505], Pt = 0;
void sieve() {
register int i, j, k;
SET(1);
int n = 500;
for(i = 2; i <= n; i++) {
if(!GET(i)) {
for(k = n/i, j = i*k; k >= i; k--, j -= i)
SET(j);
P[Pt++] = i;
}
}
}
int main() {
sieve();
int testcase, n;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &n);
int f[505][505] = {};
long long x;
for(int i = 0; i < n; i++) {
scanf("%lld", &x);
for(int j = 0; j < Pt; j++)
while(x%P[j] == 0)
x /= P[j], f[j][i] ^= 1;
}
// xor gauss
int row = Pt, col = n, arb = 0;
for(int r = 0, c = 0; r < row && c < col; c++) {
int k = r;
for(int j = r + 1; j < row; j++)
if(f[j][c]) k = j;
for(int j = 0; j < col; j++)
swap(f[r][j], f[k][j]);
if(f[r][c] == 0) {arb++;continue;}
for(int j = 0; j < row; j++) {
if(r == j) continue;
if(f[j][c]) {
for(int k = col; k >= c; k--)
f[j][k] = f[j][k] ^ f[r][k];
}
}
r++;
}
printf("%lld\n", (1LL<<arb) - 1);
}
return 0;
}
Read More +

UVa 11539 - Another Word Game

Problem

This is just another word game. You are given a dictionary of words. Each of the word has a weight W, which is an integer value. You are given another string S. Initially your score is zero. In each turn you can mark some consecutive characters. If these consecutive characters create a word in the given dictionary, corresponding weight will be added to your score, otherwise a penalty P will be subtracted word length times from your score. Here word length is number of character in a word, and P is an integer value. What is the maximum score you can gain?

Note that your have to make a move until all characters of S are marked, and you cannot mark one character more than once.

Input

Input will start with an integer number T (T≤20), which indicates the number of test case. Each test case starts with two integer N (N ≤ 10000) and P (0 ≤ P ≤ 10000). Here N is the number of words in the dictionary and P is the value of Penalty. Each of the next N lines will contain a word and corresponding integer weight W (0 ≤ W ≤ 10000). No word of this dictionary will contain more than 100 characters, and a word will only contain lower case alphabet (‘a’, ‘b’, … ,’z’). The last line of the input will contain string S. S will not contain more than 10000 characters, and will contain only lower case letters.

Output

For each test case you have to output one line which “Case #:” where # is replaced by the case number, then a space, then the maximum score.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
3
2 5
ab 2
cd 3
abcd
3 5
ab 2
cd 3
bc 16
abcd
1 100
abd 1
abcd

Output for Sample Input

1
2
3
Case 1: 5
Case 2: 6
Case 3: -400

Solution

題目描述:

給一個主子串 S,可以由其他小字串組合而成,這些小字串可以重複使用,每次使用可以得到相對應的單位獲益,但它們彼此之間不能重疊,如果 S 有一個字符沒有匹配,將會被罰款 W 單位。

求一個最高獲益的值為何?

題目解法:

由於考慮 dp[i] 已經匹配長度為 i 的時候,轉移會在字串匹配的時候速度非常慢,因此可以利用字串匹配的特性,對於所有小字串建一個 trie,接著建造出 AC 自動機,可以藉由失敗指針中快速找到當前有多少可以轉移的字符串可以串接。

但問題可能會在小字串長度太長效率下降,AC 只是剛好!也有人直接用 trie 搭配走訪就過去了,對於位置 i,從 root 開始往下走,一直走到位置 j,並且轉移,直到 trie 沒辦法走下去,保證不會有其他匹配情況。

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
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <map>
#define maxKind 26
using namespace std;
struct Node{
Node *fail;
Node *next[maxKind];
int cnt;
vector< pair<int, int> > attr;
Node() {
fail = NULL;
cnt = 0;
memset(next, 0, sizeof(next));
}
};
void build_Trie(const char* str, Node *root, pair<int, int> val) {
Node *p = root;
int i = 0, idx;
while(str[i]) {
idx = str[i] - 'a';
if(p->next[idx] == NULL)
p->next[idx] = new Node();
p = p->next[idx];
i++;
}
p->cnt++;
p->attr.push_back(val);
}
void build_AC_automation(Node *root) {
root->fail = NULL;
queue<Node*> Q;
Q.push(root);
Node *tn, *p;
while(!Q.empty()) {
tn = Q.front();
Q.pop();
for(int i = 0; i < maxKind; i++) {
if(tn->next[i] == NULL)
continue;
Q.push(tn->next[i]);
p = tn->fail;
while(p != NULL && p->next[i] == NULL)
p = p->fail;
if(p == NULL)
tn->next[i]->fail = root;
else
tn->next[i]->fail = p->next[i];
}
}
}
void free_AC_automation(Node *root) {
queue<Node*> Q;
Q.push(root);
Node *tn, *p;
while(!Q.empty()) {
tn = Q.front();
Q.pop();
for(int i = 0; i < maxKind; i++) {
if(tn->next[i] != NULL) {
Q.push(tn->next[i]);
}
}
free(tn);
}
}
void query(const char* str, Node *root, int P) {
Node *tn = root, *p;
int n = strlen(str);
int dp[100005] = {};
for(int i = 0, idx; i < n; i++) {
idx = str[i] - 'a';
dp[i + 1] = dp[i] - P;
while(tn->next[idx] == NULL && tn != root)
tn = tn->fail;
tn = tn->next[idx];
tn = (tn == NULL) ? root : tn;
p = tn;
while(p != root) {
if(p->cnt) {
for(vector< pair<int, int> >::iterator it = p->attr.begin();
it != p->attr.end(); it++) {
dp[i + 1] = max(dp[i + 1], dp[i - it->first + 1] + it->second);
}
}
p = p->fail;
}
}
printf("%d\n", dp[n]);
}
char buf[100001];
int main() {
int testcase, N, P, val, cases = 0;
scanf("%d", &testcase);
while(testcase--) {
Node *root = new Node();
scanf("%d %d", &N, &P);
for(int i = 0; i < N; i++) {
scanf("%s %d", buf, &val);
build_Trie(buf, root, make_pair(strlen(buf), val));
}
build_AC_automation(root);
scanf("%s", buf);
printf("Case %d: ", ++cases);
query(buf, root, P);
free_AC_automation(root);
}
return 0;
}
Read More +

UVa 11523 - Recycling

Problem

Recycling involves processing used materials into new products in order to prevent the waste of potentially useful materials.

Recycling materials include things like glass, paper, plastic, metal and textiles. There are some materials that can’t be recycled such as Aerosol Cans. Aerosol cans that are not empty may leak or explode during the sorting and baling processes of recycling.

You are given a list of materials to be recycled. The materials are initially aligned in a line one after another. For every type of recyclable-material there is a corresponding bin. You are required to place each recyclable-material in its corresponding bin.

Example:

paper – glass – paper – aerosol – paper

In the example above, there are two types of recyclable-materials (paper & glass) and one type of non-recyclable-material. If we were to pick each material one by one and throw them in the bins, we would require 4 moves since there are 4 recyclable-materials. However, if we remove consecutive items in one move, provided they are of the same type, we could achieve the desired task in lesser number of moves.

Let’s see how this can be done: If we remove the glass first then the first two papers appear side by side enabling them to be moved together in the next move. Then we just have one paper remaining at the end and that requires a further move. This accumulates to a figure of 3 moves.

Illustration:

1
2
3
4
# Start : paper – glass – paper – aerosol – paper
# Move 1 : paper – paper – aerosol – paper [ after removing glass ]
# Move 2 : aerosol – paper [ after removing first 2 papers ]
# Move 3 : aerosol [ after removing the last paper ]

Input

The first line of input is an integer T(T<50) that indicates the number of test cases. Each case starts with an integer N(N<100). The next line contains the names of N materials. The name of each material is a string containing only characters from the set [a..z] and [A..Z] and the length of each is at most 20. A recyclable-material is represented by lowercase letters only and that of non-recyclable-material by uppercase letters only.

Output

For each case, output the case number followed by the minimum number of moves required to clean up all the recyclable-materials meeting the constraints mentioned above.

Sample Input

1
2
3
4
5
6
7
3
5
paper glass paper AEROSOL paper
4
icpc icpc icpc icpc
3
NO RECYCLABLE MATERIALS

Output for Sample Input

1
2
3
Case 1: 3
Case 2: 1
Case 3: 0

Solution

題目描述:

現在把垃圾放置在一維空間,垃圾分成可回收和不可回收兩種,我們可以一次將連續個回收物拾起清除 (整個區間內的回收種類都要相同。) 並且放置回收桶。

用小寫表示可回收的種類分布,大寫為不可回收。求操作次數最少為何。

題目解法:

這一題比 UVa 10559 - Blocks 還要稍微簡單一點,可以在 O(n^3) 以內完成。UVa 10559 - Blocks 的計分方式多了一次清除的個數平方,最大化分數。

在這裡我們只需要將狀態改為,考慮區間 [l, r] 最左側 A[l] 項目是否要清除,否則將要等待 [l+1, i] 之間的項目清除之後,與 [i+1, ...] 一起清除。

  • 直接移除最左側
  • 等待中間一段的移除,隨後跟著 [i+1, ...] 最左側的一起清除。

因此轉移方程

$dp[l, r] = min(min(dp[l+1, r] + 1), min(dp[l+1, i] + dp[i+1, r]))$

記住中間轉移要保證一定取得連續相同且皆可回收,為了方便計算,連續相同的壓縮起來,直接考慮是否可回收即可。

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
// http://mypaper.pchome.com.tw/zerojudge/post/1326837348
#include <stdio.h>
#include <map>
#include <iostream>
#include <algorithm>
#include <ctype.h>
using namespace std;
int A[105], B[105];
int dp[105][105]; //[l][r][___{l, r}]
char used[105][105] = {}, usedcases = 0;
int dfs(int l, int r) {
if(l > r) return 0;
if(used[l][r] == usedcases)
return dp[l][r];
int &ret = dp[l][r];
used[l][r] = usedcases;
if(A[l] == -1) {
ret = dfs(l + 1, r);
return ret;
}
ret = dfs(l+1, r) + 1;
for(int i = l+1; i <= r && A[i] != -1; i++) {
if(A[i] == A[l]) {
ret = min(ret, dfs(l+1, i-1) + dfs(i, r));
}
}
return ret;
}
int main() {
int testcase, n, m;
int cases = 0, i;
char material[105][32];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &n);
map<string, int> R;
for(int i = 0; i < n; i++) {
scanf("%s", material[i]);
if(islower(material[i][0]))
R[material[i]] = 0;
}
int size = 0;
for(map<string, int>::iterator it = R.begin(); it != R.end(); it++)
it->second = size++;
for(int i = 0; i < n; i++) {
if(isupper(material[i][0]))
A[i] = -1;
else
A[i] = R[material[i]];
}
for(i = 1, B[0] = 1, m = 0; i < n; i++) {
if(A[m] == A[i])
B[m]++;
else {
A[++m] = A[i], B[m] = 1;
}
}
usedcases++;
printf("Case %d: %d\n", ++cases, dfs(0, m));
}
return 0;
}
Read More +