poj1179 Polygon【区间DP】

Polygon

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions:6633   Accepted: 2834

Description

Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (addition) or the symbol * (product). The edges are numbered from 1 to N. 

On the first move, one of the edges is removed. Subsequent moves involve the following steps: 
?pick an edge E and the two vertices V1 and V2 that are linked by E; and 
?replace them by a new vertex, labelled with the result of performing the operation indicated in E on the labels of V1 and V2. 
The game ends when there are no more edges, and its score is the label of the single vertex remaining.

Consider the polygon of Figure 1. The player started by removing edge 3. After that, the player picked edge 1, then edge 4, and, finally, edge 2. The score is 0. 

Write a program that, given a polygon, computes the highest possible score and lists all the edges that, if removed on the first move, can lead to a game with that score.

Input

Your program is to read from standard input. The input describes a polygon with N vertices. It contains two lines. On the first line is the number N. The second line contains the labels of edges 1, ..., N, interleaved with the vertices‘ labels (first that of the vertex between edges 1 and 2, then that of the vertex between edges 2 and 3, and so on, until that of the vertex between edges N and 1), all separated by one space. An edge label is either the letter t (representing +) or the letter x (representing *).

3 <= N <= 50 
For any sequence of moves, vertex labels are in the range [-32768,32767].

Output

Your program is to write to standard output. On the first line your program must write the highest score one can get for the input polygon. On the second line it must write the list of all edges that, if removed on the first move, can lead to a game with that score. Edges must be written in increasing order, separated by one space.

Sample Input

4
t -7 t 4 x 2 x 5

Sample Output

33
1 2

Source

IOI 1998

题意:

给一个n个顶点n条边的多边形,顶点上有一个整数值,边上有一个字符表示+ 或者 *。首先删除一条边,然后每次对两个顶点进行合并,用一个顶点代替这两个顶点,顶点的值是这两个顶点运算的结果,运算符为连接这两个顶点的边。最后只剩下一个顶点,问这个顶点最大值会是多少,以及得到这个结果的删边方法。

思路:

删除了一条边后,就类似于石子合并(https://www.cnblogs.com/wyboooo/p/9757387.html)这道题了。

不同之处在于因为有负数和乘法的存在,最大值有可能是由两个最小值相乘得到的。因此需要同时记录最大值和最小值。【已经遇到好多有负数、乘法要记录最大值最小值的问题了,需要注意!】

最开始需要枚举删掉的边,一个好方法是,将原来的数组在末尾复制一遍。从1~n跑一遍成为枚举,最后找dp[i][i+n-1]的最大值就行了。

这种“任意选择一个位置断开,复制形成2倍长度的链”的方法,是解决DP中环形结构的常用手段之一。

 1 //#include <bits/stdc++.h>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<stdio.h>
 6 #include<cstring>
 7 #include<map>
 8
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 typedef long long LL;
12
13 int n;
14 const int maxn = 55;
15 int num[maxn * 2];
16 char op[maxn * 2];
17 int dp[maxn * 2][maxn * 2][2];
18
19 int main()
20 {
21     while(scanf("%d", &n) != EOF){
22
23         for(int i = 1; i <= n; i++){
24             scanf(" %c %d", &op[i], &num[i]);
25         }
26         for(int i = n + 1; i <= 2 * n; i++){
27             op[i] = op[i - n];
28             num[i] = num[i - n];
29         }
30         for(int i = 0; i <= n * 2; i++){
31             dp[i][i][0] = dp[i][i][1] = num[i];
32             for(int j = i + 1; j <= 2 * n; j++){
33                 dp[i][j][0] = -inf;
34                 dp[i][j][1] = inf;
35             }
36         }
37
38         for(int len = 2; len <= n; len++){
39             for(int l = 1; l <= 2 * n - len + 1; l++){
40                 int r = l + len - 1;
41                 for(int k = l; k < r; k++){
42
43                     int res1, res2;
44                     if(op[k + 1] == ‘t‘){
45                         res1 = dp[l][k][0] + dp[k + 1][r][0];
46                         res2 = dp[l][k][1] + dp[k + 1][r][1];
47                     }
48                     else{
49                         res1 = dp[l][k][0] * dp[k + 1][r][0];
50                         res2 = dp[l][k][1] * dp[k + 1][r][1];
51                         dp[l][r][0] = max(dp[l][r][0], dp[l][k][1] * dp[k + 1][r][1]);
52                         dp[l][r][1] = min(dp[l][r][1], dp[l][k][0] * dp[k + 1][r][1]);
53                         dp[l][r][1] = min(dp[l][r][1], dp[l][k][1] * dp[k + 1][r][0]);
54                     }
55                     dp[l][r][0] = max(dp[l][r][0], res1);
56                     dp[l][r][1] = min(dp[l][r][1], res2);
57                 }
58             }
59         }
60
61         int ans = -inf;
62         for(int i = 1; i <= n; i++){
63             ans = max(dp[i][i + n - 1][0], ans);
64         }
65         printf("%d\n", ans);
66         bool flag = false;
67         for(int i = 1; i <= n; i++){
68             if(dp[i][i + n - 1][0] != ans)continue;
69             if(flag){
70                 printf(" ");
71             }
72             else{
73                 flag = true;
74             }
75             printf("%d", i);
76         }
77         printf("\n");
78     }
79     return 0;
80 }

原文地址:https://www.cnblogs.com/wyboooo/p/9757740.html

时间: 2024-08-29 21:35:11

poj1179 Polygon【区间DP】的相关文章

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

POJ 1179 Polygon 区间DP

链接:http://poj.org/problem?id=1179 题意:给出一个多边形,多边形的每个顶点是一个数字,每条边是一个运算符号"+"或者"x".要求的过程如下,手下移除一条边,即这条边不做运算.之后每次移除一条边,将其两边的数字进行对应边的运算,用得到的数字来替代原来的两个点.要求所有边都移除以后得到的最大的答案. 思路:典型的区间DP,在过程中每次操作的处理方式为dp_max[i][j]=dp[i][k]*dp[k+1][j],dp_max[i][j]

poj1179 环形+区间dp

因为要用到模,所以左起点设置为0比较好 #include<iostream> #include<cstdio> #include<cstring> #define INF 0x3f3f3f3f using namespace std; char c[55]; int val[55],dp_max[55][55],dp_min[55][55]; int cal(char x,int a,int b){if(x=='t')return a+b;return a*b;} in

poj1179 区间dp(记忆化搜索写法)有巨坑!

http://poj.org/problem?id=1179 Description Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (add

UVA 1331 Minimax Triangulation 区间DP

区间DP: 将一个多边形三角剖分,让可以得到的最大三角形的面积最小 dp[i][j]表示从i点到j点的最优值,枚举中间点k dp[i][j]=min(dp[i][j],max(area(i,j,k),max(dp[i][k],dp[k][j]))); 注意如果中间三角形i-j-k中有其他的点,这样的三角形是不可以剖分的 Minimax Triangulation Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld

POJ1179——Polygon

Polygon Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 4975   Accepted: 2090 Description Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an int

zoj 3537 Cake (凸包判定+区间dp)

Cake Time Limit: 1 Second      Memory Limit: 32768 KB You want to hold a party. Here's a polygon-shaped cake on the table. You'd like to cut the cake into several triangle-shaped parts for the invited comers. You have a knife to cut. The trace of eac

POJ1179Polygon(区间dp)

啊~~ 被dp摁在地上摩擦的人 今天做了一道区间dp的题(POJ1179Polygon) 题目: Polygon Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6951   Accepted: 2975 Description Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure

uva 10003 Cutting Sticks 简单区间dp

// uva 10003 Cutting Sticks 区间dp // 经典的区间dp // dp(i,j)表示切割小木棍i-j所需要的最小花费 // 则状态转移为dp(i,j) = min{dp(i,k) + dp(k,j) + a[j]-a[i]) // 其中k>i && k<j // a[j] - a[i] 为第一刀切割的代价 // a[0] = 0,a[n+1] = L; // dp数组初始化的时候dp[i][i+1]的值为 0,这表示 // 每一段都已经是切割了的,不

黑书例题 Fight Club 区间DP

题目可以在bnuoj.soj等OJ上找到. 题意: 不超过40个人站成一圈,只能和两边的人对战.给出任意两人对战的输赢,对于每一个人,输出是否可能是最后的胜者. 分析: 首先序列扩展成2倍,破环成链. dp[i][j]表示i和j能够相遇对打,那么dp[i][i+n]为真代表可以成为最后胜者. 枚举中间的k,若i和j都能和k相遇,且i和j至少一人能打赢k,那么i和j可以相遇. 复杂度o(n^3) 1 #include<cstdio> 2 #include<cstring> 3 usi