poj 1179 polygon

题目大意:
有一个n个点的环,每条边上有加号或乘号,然后这条边所连的两个点的权值就依据这条边上的符号来进行运算,将运算的结果作为一个新的节点。

问先去掉一条边,最后将所有边都进行运算,最后得到的最终点的权值最大是多少(输入时t表示该边为加号,x表示该边为乘号


思路:
首先分析题目可以看出应为dp。题目要求删除一条边后的最大得分,那么我们只要求出来从第i个顶点到第i-1个顶点(走一大圈)的最大分数就好了

可以想到列dp[i][k]表示以第i个顶点为起点顺时针走k个顶点的最大得分。(k>=1)

可以枚举分割点求出dp[i][k],又因为是一个环,枚举分割点较为麻烦,因此枚举分割长度j:

得到dp方程 dp[i][j]与dp[i+j][k-j]之间运算(1<=j<k)

但是有一个问题 因为存在负数,所以可能有两个负数相乘得到最大值

因此我们还需要求出以第i个顶点为起点顺时针走k个顶点的最小得分

这样就用两个数组maxf,minf记录一下

其中minf中两个乘的情况有些麻烦:求五个情况的最小值(minf[i][len],minf[i][j]*minf[(i+j)%n][len-j],minf[i][j]*maxf[(i+j)%n][len-j],maxf[i][j]*maxf[(i+j)%n][len-j],maxf[i][j]*minf[(i+j)%n][len-j])

最后搞一下长度为n就好了

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<memory.h>
 7 #include<vector>
 8 #include<queue>
 9 #include<cstdlib>
10 #define MAXN 55
11 using namespace std;
12 bool edge[MAXN];
13 char ch;
14 int ans,maxf[55][55],minf[55][55],a,n;
15 int main()
16 {
17     scanf("%d",&n);
18     for(int i=0;i<MAXN;i++)
19         for(int j=0;j<MAXN;j++) {maxf[i][j]=-214748364;minf[i][j]=214748364;}
20     for(int i=0;i<n;i++) 
21     {
22         cin>>ch>>a;
23         if(ch=='t') edge[i]=true;
24         maxf[i][1]=minf[i][1]=a;
25     }
26     for(int len=2;len<=n;len++)
27     {
28         for(int i=0;i<n;i++)
29         {
30             for(int j=1;j<len;j++)
31             {
32                 if(edge[(i+j)%n]==true) 
33                 {
34                     maxf[i][len]=max(maxf[i][len],maxf[i][j]+maxf[(i+j)%n][len-j]);
35                     minf[i][len]=min(minf[i][len],minf[i][j]+minf[(i+j)%n][len-j]);
36                 }
37                 if(edge[(i+j)%n]==false) 
38                 {
39                     maxf[i][len]=max(maxf[i][len],max(maxf[i][j]*maxf[(i+j)%n][len-j],minf[i][j]*minf[(i+j)%n][len-j]));
40                     minf[i][len]=min(minf[i][len],min(min(minf[i][j]*minf[(i+j)%n][len-j],minf[i][j]*maxf[(i+j)%n][len-j]),min(maxf[i][j]*maxf[(i+j)%n][len-j],maxf[i][j]*minf[(i+j)%n][len-j])));
41                 }
42             }
43             if(len==n) ans=max(ans,maxf[i][len]);
44         }
45     }
46     printf("%d\n",ans);
47     bool flag=false;
48     for(int i=0;i<n;i++)
49     {
50         if(maxf[i][n]==ans&&flag==true) printf(" %d",i+1);
51         if(maxf[i][n]==ans&&flag==false) {printf("%d",i+1);flag=true;}
52     }
53 }
View Code

 

 

 

转载于:https://www.cnblogs.com/yyc-jack-0920/p/7111689.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值