ZOJ Monthly, July 2010 部分题目解题报告

http://acm.zju.edu.cn/onlinejudge/showProblems.do?contestId=1&pageNumber=24

zoj 3352 - 3361

zoj 3352 Boring Board Game

题意:50个点有向无环图,每个点有0-2的数字,有黑白两旗,两个人玩游戏,轮流沿着边移动一个旗子,白旗使得赌注增加抵达点的数字,黑旗反之。无法移动旗子的人输,需要给赢的人赌注,赌注可能为负,问先手的最大收益,以及能获得此收益的第一步方案数。

分析:点数很少,而且数字变化范围小,又是有向无环图,启发我们搜索&&DP。dp[i][j][k]表示白旗在i,黑旗在j,赌注为k,现在先手的人的最大收益,记忆化搜索。因为两个人玩游戏,终结态时值为-k,状态转移取个负号,即先手转换。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 using namespace std;
 5 
 6 int n, m, x, y, a, b;
 7 vector<int> E[55];
 8 int dp[55][55][210], ct[55][55][210];
 9 int s[55];
10 int dfs(int w, int b, int k)
11 {
12     if (ct[w][b][100+k] != -1) return dp[w][b][100+k];
13     dp[w][b][100+k] = -21474836; 
14     if (E[w].empty() && E[b].empty()){
15         dp[w][b][100+k] = -k;
16         return -k;
17     }
18     int &ret = dp[w][b][100+k]; int &cnt = ct[w][b][100+k];
19     vector<int>::iterator i;
20     for (i = E[w].begin(); i != E[w].end(); i ++){
21         int tmp = -dfs(*i, b, k + s[*i]);
22         if (tmp > ret){
23             ret = tmp;
24             cnt = 1;
25         }
26         else if (tmp == ret) cnt++;
27     }
28     for (i = E[b].begin(); i != E[b].end(); i ++){
29         int tmp = -dfs(w, *i, k - s[*i]);
30         if (tmp > ret){
31             ret = tmp;
32             cnt = 1;
33         }
34         else if (tmp == ret) cnt++;
35     }
36     return ret;
37 }
38 int main()
39 {
40     while(scanf("%d %d %d %d", &n, &m, &x, &y) != EOF)
41     {
42         for (int i = 0; i < n; i++){
43             scanf("%d", &s[i]);
44             E[i].clear();
45         }
46         for (int i = 0; i < m; i++){
47             scanf("%d %d", &a, &b);
48             E[a].push_back(b);
49         }
50         memset(ct, -1, sizeof(ct));
51         dfs(x, y, 1);
52         printf("%d %d\n", dp[x][y][101], ct[x][y][101]);
53     }
54     return 0;
55 }

 

 

zoj 3355 3356 两道很恶心的题目,精度问题。。代码都是抄的标程= =。。

推的公式是ax<x+y+z,by<x+y+z,cz<x+y+z,然后合并得到1/a+1/b+1/c<1,然后bc+ac+ab<abc,左边是投的钱,右边是收益(胜平负都是abc)。

3356的优化是让大部分的钱按比率投,之后一个一个枚举。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 int T;
 6 long long a, aa, b, bb, c, cc;
 7 int main()
 8 {
 9     scanf("%d", &T);
10     while(T--)
11     {
12         scanf("%lld.%lld %lld.%lld %lld.%lld", &a, &aa, &b, &bb, &c, &cc);
13         a = a * 100 + aa;
14         b = b * 100 + bb;
15         c = c * 100 + cc;
16         if (100ll * (a*b + b*c + a*c) < a*b*c)
17             puts("Aha");
18         else puts("No way");
19     }
20     return 0;
21 }
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int T;
 7 long long a, b, s, c[3], d[3], e[3], ans;
 8 int main()
 9 {
10     scanf("%d", &T);
11     while(T--)
12     {
13         scanf("%lld", &s);
14         for (int i = 0; i < 3; i++){
15             scanf("%lld.%lld", &a, &b);
16             c[i] = a * 100 + b;
17         }
18 
19         ans = 0;
20         d[0] = d[1] = d[2] = 0;
21         e[0] = e[1] = e[2] = 0;
22         for (int i = 1; i <= s; i++){
23             int k = min_element(e, e+3) - e;
24             ++d[k];
25             e[k] = d[k] * c[k] / 100;
26             ans = max(ans, *min_element(e, e+3) - i);
27         }
28         printf("%lld\n", ans + s);
29     }
30     return 0;
31 }

 

 

zoj 3358 Green Dam Girl

题意:题面实在猥琐。。大意就是n个点,在每个点停留获得收益,连续停留1,2,3及以上单位时间的收益不同,点与点有有向边,边有转移费用,问d时间的最大收益。

分析:dp方程还是比较好想的。因为在i和i+1时间可以连续走好几条边,点数只有100,先用floyd求出点到点最短路。dp[i][j][k]表示在第i的时间在第j个点,停留k时间的最大收益,然后转移就可以了。注意数据有在某点只停留1单位时间的收益很高的情况,导致出现走一个环回到该点,刷新停留时间的策略。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstdlib>
 7 #include<set>
 8 #include<map>
 9 #include<queue>
10 #include<ctime>
11 #include<string>
12 using namespace std;
13 
14 int n, d;
15 int cost[110][110];
16 int dp[110][110][5];
17 int night[110][5];
18 int main()
19 {
20     while(scanf("%d%d", &n, &d) != EOF)
21     {
22         memset(cost, -1, sizeof(cost));
23         int m, y, c;
24         for (int i = 0; i < n; i++){
25             for (int j = 1; j <= 3; j++)
26                 scanf("%d", &night[i][j]);
27             scanf("%d", &m);
28             for (int j = 0; j < m; j++){
29                 scanf("%d %d", &y, &c);
30                 cost[i][y] = c;
31             }
32         }
33         for (int k = 0; k < n; k++)
34             for (int i = 0; i < n; i++){
35                 if (cost[i][k] == -1) continue;
36                 for (int j = 0; j < n; j++){
37                     if (cost[k][j] == -1) continue;
38                     if (cost[i][j] == -1 || cost[i][j] > cost[i][k] + cost[k][j])
39                         cost[i][j] = cost[i][k] + cost[k][j];
40                 }
41             }
42         //for (int i = 0; i < n; i++)
43         //    for (int j = 0; j < n; j++)
44         //        printf("%d %d %d\n", i, j, cost[i][j]);
45         memset(dp, -1, sizeof(dp));
46         dp[1][0][1] = night[0][1];
47         dp[2][0][2] = night[0][1] + night[0][2];
48         for (int i = 1; i < n; i++)
49             if (cost[0][i] != -1 && dp[1][0][1] >= cost[0][i]){
50                 dp[2][i][1] = dp[1][0][1] - cost[0][i] + night[i][1];
51             }
52         d--;
53         for (int i = 2; i < d; i++)
54             for (int j = 0; j < n; j++){
55                 for (int k = 1; k <= 3; k++){    
56                     //printf("%d %d %d %d\n", i, j, k, dp[i][j][k]);
57                     if (dp[i][j][k] == -1) continue;
58                     int tmp = k+1;
59                     if (tmp > 3) tmp = 3;
60                     dp[i+1][j][tmp] = max(dp[i+1][j][tmp], dp[i][j][k] + night[j][tmp]);
61                     for (int to = 0; to < n; to++){
62                         if (cost[j][to] != -1 && dp[i][j][k] >= cost[j][to]){
63                             dp[i+1][to][1] = max(dp[i+1][to][1], dp[i][j][k] - cost[j][to] + night[to][1]);
64                         }
65                     }
66                 }
67             }
68         int ans = 0;
69         for (int i = 0; i < n; i++)
70             for (int k = 1; k <= 3; k++)
71                 ans = max(ans, dp[d][i][k]);
72         printf("%d\n", ans);
73     }
74     return 0;
75 }

 

 

zoj 3359 Penalties Kick 模拟题,没太多好说的,踢完一个球判断一次。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int T;
 7 int home[50], away[50];
 8 char tmp[10];
 9 char win[2][10] = {"home", "away"};
10 void output(int cas, int winner, int sh, int sa)
11 {
12     printf("Match %d:\n", cas);
13     printf("Winner: %s\n", win[winner]);
14     printf("Score: %d:%d\n", sh, sa);
15 }
16 int main()
17 {
18     scanf("%d", &T);
19     for (int cas = 1; cas <= T; cas++)
20     {
21         int sh, sa, winner;
22         bool flag = false;
23         for (int i = 1; i <= 11; i++){
24             for (int j = 0; j < 3; j++){
25                 scanf("%s", tmp);
26                 if (tmp[0] == 'y'){
27                     home[i+j*11] = 1;
28                 }
29                 else home[i+j*11] = 0;
30             }
31         }
32         for (int i = 1; i <= 11; i++){
33             for (int j = 0; j < 3; j++){
34                 scanf("%s", tmp);
35                 if (tmp[0] == 'y'){
36                     away[i+j*11] = 1;
37                 }
38                 else away[i+j*11] = 0;
39             }
40         }
41         sh = sa = 0;
42         for (int i = 1; i <= 5; i++){
43             sh += home[i];
44             if (sh - sa > 5 - i + 1){
45                 winner = 0;
46                 flag = true;
47                 break;
48             }
49             if (sa - sh > 5 - i){
50                 winner = 1;
51                 flag = true;
52                 break;
53             }
54             sa += away[i];
55             if (sh - sa > 5 - i){
56                 winner = 0;
57                 flag = true;
58                 break;
59             }
60             if (sa - sh > 5 - i){
61                 winner = 1;
62                 flag = true;
63                 break;
64             }
65         }
66         if (flag){
67             output(cas, winner, sh, sa);
68             continue;
69         }
70         for (int i = 6; i <= 33; i++){
71             sh += home[i];
72             sa += away[i];
73             if (sh > sa){
74                 winner = 0;
75                 break;
76             }
77             if (sa > sh){
78                 winner = 1;
79                 break;
80             }
81         }
82         output(cas, winner, sh, sa);
83     }
84     return 0;
85 }

 

 

 

zoj 3360 Stranger Calendar II

题意:题意至今不明。。大概就是要求n1, n2 …使得1/n1-1/n1n2+1/n1n2n3-…等于给定的A/B

分析:

只考虑A/B < 1/2的情况,另一种情况解是相同的。对于A/B,假设n1 = C,则得到A/B-1/C = AC-B/BC,后面的分数分母都有C,所以乘上C,然后因为相邻项的运算相反,我们再取相反数,得到B-AC/B,这个就是新的A/B,n2就用同n1一样的方法求解,也就是一个递归的过程。题目要求所用分数不超过5个,且希望解最少,所以用迭代加深搜索,出口是分子为0或是达到限制层数。每层枚举,C要满足 0 <= B-AC/B <= 1/2。

还有一种不用这种递归思想的是一步步枚举新的分数的因子,随着所用分数增多,肯定是不断逼近,而且是一上一下震荡式地逼近A/B的,新加上的分数要让curA/curB > A/B,新减去的分数要让curA/curB < A/B,以此剪枝,也可以通过。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int T;
 7 int a, b;
 8 int ans[100];
 9 int dfs(int dep, int lim, int cura, int curb)
10 {
11     if (cura == 0) return dep;
12     if (dep == lim) return 0; 
13     int l = max(curb/(2*cura) - 1, 2), r = curb/cura;
14     for (int i = l; i <= r; i++){
15         ans[dep] = i;
16         int newa = curb - cura * i, newb = curb;
17         int tmp = __gcd(newa, newb);
18         newa /= tmp; newb /= tmp;
19         tmp = dfs(dep+1, lim, newa, newb);
20         if (tmp) return tmp;
21     }
22     return 0;
23 }
24 int main()
25 {
26     scanf("%d", &T);
27     while(T--)
28     {
29         scanf("%d %d", &a, &b);
30         int gcd = __gcd(a, b);
31         a /= gcd; b /= gcd;
32         if (a > b - a) a = b - a;
33         int lim, size;
34         for (lim = 1; lim < 6; lim ++){
35             size = dfs(0, lim, a, b);
36             if (size) break;
37         }
38         if (lim == 6){
39             puts("Too complex");
40             continue;
41         }
42         else{
43             for (int i = 0; i < size; i++)
44                 printf("%d%c", ans[i], i+1==size? '\n': ' ');
45         }
46     }
47     return 0;
48 }

 

posted @ 2014-08-03 17:09  james47  阅读(258)  评论(0编辑  收藏  举报