[dp之路]7.25test

题意:

 

题目一:传球游戏

ball.c/cpp/pas

Time Limit:1s Memory Limit:256M

题目描述:

上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。

游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到了小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有3个同学1号、2号、3号,并且假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共2种。

输入格式

输入文件ball.in共一行,有两个用空格隔开的整数n,m
40%的数据满足:3<=n<=30,1<=m<=20

100%的数据满足:3<=n<=30,1<=m<=30

输出格式

输出文件ball.out共一行,有一个整数,表示符合题意的方法数。

样列输入

3 3

样列输出

2

一道简单的dp

设dp[i][j]是第i步到达第j个位置的方法数,那么dp[i][j] = dp[i - 1][j + 1] + dp[i - 1][j - 1]

由于是环形,所以注意边界就好了

#include<iostream>
#include<cstdio>
using namespace std;

int n,m;
int dp[50][50];
int main()
{
    freopen("ball.in", "r", stdin);
    freopen("ball.out", "w", stdout);
    scanf("%d%d", &n, &m);
    dp[0][1] = 1;
    for(int i = 1; i <= m; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            dp[i][j] = dp[i - 1][(j + 1) > n ? 1 : j + 1] + dp[i - 1][(j - 1) <= 0 ? n : j - 1];
        }
    }
    printf("%d",dp[m][1]);
    return 0;
}

其实dfs也挺简单的

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 
 5 int ans = 0;
 6 int n,m;
 7 
 8 void dfs(int j, int p)
 9 {
10     //printf("%d %d\n",j,p);
11     if(j == 0 && p == 1){
12         ans++;
13         //printf("++\n");
14         return ;
15     }
16     if(j == 0 && p != 1)return ;
17     if(p + 1 <= n)dfs(j - 1, p + 1);
18     if(p + 1 > n)dfs(j - 1, 1);
19     if(p - 1 > 0)dfs(j - 1, p - 1);
20     if(p - 1 < 1)dfs(j - 1, n);
21 }
22 int main()
23 {
24     freopen("ball.in", "r", stdin);
25     freopen("ball1.out", "w", stdout);
26     scanf("%d%d", &n ,&m);
27     dfs(m, 1);
28     printf("%d",ans);
29     return 0;
30 }
View Code

题目二: 纯洁的买卖

sale.c/cpp/pas

Time Limit:1s Memory Limit:256M

 

题目描述:

ALEJ并不是财迷,但是作为纯洁党的伟大领袖,不挣钱,纯洁的事业怎么能坚持下去!纯洁党现在已经有M(1<=M<=100000)元经费了。ALEJ有一个富II代朋友,叫做HSW,HSW特别喜欢高价收藏一些餐巾纸(mzd用过的)、袜子(恐龙穿过的)、马桶垫(还珠格格坐过的)、红领巾(毛新宇戴过的)等等,总之,没有他不买的。因此ALEJ想通过HSW这个大财主,去实现倒买倒卖拥有尽可能多的钱。

有N(1<=N<=100)件物品供他选择,

ALEJ每件物品的买入价为c[i](1<=c[i]<=100000)元,

HSW的收藏价为r[i](1<=r[i]<=100000)元。

每向HSW卖出一件物品i之后,还要向政府上交c[i]元的税。每种物品的数量都是无限的。

ALEJ想知道,通过一次买卖(种类、数量没有限制)后,纯洁党的经费能有多少。

输入格式

第一行两个整数,N,M。之后N行,每行两个整数:c[i],r[i]

输出格式

一个整数,表示一次买卖后手里最多的钱数。

样例输入

3 17

2 4

5 6

3 7

样例输出

22

 

 

思路:

完全裸得不能再裸的完全背包,稍微改下就行了。。。。。话说居然看错题,直接打纯的完全背包。。而且居然答案跟样例一样!!!!

设dp[i]为还剩i元经费的赚的最大值,c[i] 为第i件物品的买入,b[i]为交了税后的纯收入;

然后直接完全背包,最后输出dp[m] + m,

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 int c[200],b[200];
 7 int n, m;
 8 long long dp[100000 + 10];
 9 
10 int main()
11 {
12     freopen("sale.in", "r", stdin);
13     freopen("sale.out", "w", stdout);
14     scanf("%d%d", &n ,&m);
15     memset(dp,0,sizeof(dp));
16     for(int i = 1; i <= n; i++){
17         scanf("%d%d", &c[i], &b[i]);
18         b[i] -= 2 * c[i];
19     }
20         
21         
22     for(int i = 1; i <= n; i++)
23     {
24         for(int j = c[i]; j <= m; j++)
25         dp[j] = max(dp[j], dp[j - c[i]] + (long long)b[i]);
26     }
27     printf("%I64d",dp[m] + m);
28     return 0;
29 }
View Code

题目 三 : 多边形游戏

game.c/cpp/pas

Time Limit:1s Memory Limit:256M

 

题目描述

多边形游戏是一种在一个具有n个顶点的多边形上进行的游戏。每个顶点有个权值(整数)。如图1是一个n=4对应多边形,每个顶点上都有一个整数,每条边都有一个运算符+或者*,所有边按从1到n进行编号。

多边形游戏(DP)

游戏都首先移除一条边,接下来可以进行如下操作:

选择一条边E和与之相关联的点V1和V2,用一个新的点替换它们,新点上的整数为V1,V2上的整数用E上的操作符运算后的结果。

没有边时游戏结束,游戏得分就是最后剩下的那个顶点上的整数。

多边形游戏(DP)

对于图1中的多边形,如果游戏者首先去掉3,然后依次去掉1、4、2,最后得分将是0。

请你写一个程序,对于给定的多边形,计算出可能得到的最高分,并列出第一步移除哪些边可以得到这个最高分。

关于输入

输入第一行是一个正整数n(3<=n<=50),表示多边形的边数。

接下来一行是这个多边形的描述,包含n条边和n个顶点,加号边用t表示,乘号边用x表示,顶点用顶点上标的整数表示,输入按照边的编号从1到n的顺序给出。

关于输出

第一行输出可能得到的最高分。

第二行输出一些边的列表,只有第一步移除的边在这个列表中才可能得到最高分。每条边都用这个边上的编号表示,列表必须是升序的。

例子输入

4

t -7 t 4 x 2 x 5

例子输出

33

1 2

 

这道题好难好难好难。。。

由于随便去掉一条边,也就是将一条环断成一条链,有点像环形的石子归并。。。。那么我们就按那种思路去想,并且由于会出现负数,那么我们就不能单纯的只保留最大值,因为两个极小的负数相乘有可能会是个极大的数,所以我们应该保存最大值与最小值来判断。

 

若为t;绝对值最大
最大数+最大数
最小数+最小数
若为x
正数*正数
负数*负数
正数*负数
负数*正数

 

 

设dpmax[i][j][k] 为去掉第i条边,从第j条边到第k条边的合并的最大值  dpmin[i][j][k]同理

那么我们可以枚举最后一次合并的断点来转移,注意是环形,至于去掉那些边可能得到最大值,一个循环扫一遍判断是否是最大值,若是,则加入答案,不是则跳过

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 
 6 int n;
 7 char ope[50], tope[50];
 8 int num[50],tnum[50];
 9 int dpmax[50][50][50];
10 int dpmin[50][50][50];
11 int maxx;
12 int temp1,temp2,temp3,temp4;
13 
14 int main()
15 {
16     freopen("game.in", "r", stdin);
17     freopen("game.out", "w", stdout);
18     memset(dpmax, -0x3f , sizeof(dpmax));
19     memset(dpmin, 0x3f , sizeof(dpmin));
20     int i, j, k, l;
21     int path[50];
22     scanf("%d ", &n);
23     for(i=0;i<2*n;i++)
24     {
25         if(i%2 == 0)
26         cin>>ope[i/2];
27         else
28         cin>>num[(i-1)/2];
29     }
30     
31     for(i = 0; i < n; i++)
32     {
33         for(j = 0; j < n; j++)
34         {
35             tope[j] = ope[(i + 1 + j) %n ];
36             tnum[j]=num[(i + j) % n];
37         }
38         for(j = 0; j < n; j++)
39         {
40             dpmax[i][j][j] = tnum[j];
41             dpmin[i][j][j] = tnum[j];
42         }
43         for(j = 1; j <= n - 1; j++)
44         {
45             for(k = 0; k + j <= n - 1; k++)
46             {
47                 for(l = k; l < k + j; l++)//枚举断点
48                 {
49                     if(tope[l] == 't')//找最大值与最小值
50                     {
51                         temp1 = dpmax[i][k][l] + dpmax[i][l + 1][k + j];
52                         temp2 = dpmin[i][k][l] + dpmin[i][l + 1][k + j];
53                         dpmax[i][k][k + j] = max(dpmax[i][k][k + j], max(temp1, temp2));
54                         dpmin[i][k][k + j] = min(dpmin[i][k][k + j], min(temp1, temp2));
55                     }
56                     else
57                     {
58                         temp1 = dpmax[i][k][l] * dpmax[i][l + 1][k + j];
59                         temp2 = dpmin[i][k][l] * dpmin[i][l + 1][k + j];
60                         temp3 = dpmin[i][k][l] * dpmax[i][l + 1][k + j];
61                         temp4 = dpmax[i][k][l] * dpmin[i][l + 1][k + j];
62                         dpmax[i][k][k + j] = max(dpmax[i][k][k + j], max(temp1, max(temp2, max(temp3, temp4))));
63                         dpmin[i][k][k + j] = min(dpmin[i][k][k + j], min(temp1, min(temp2, min(temp3, temp4))));
64                     }
65             }
66         }
67     }
68 }
69     maxx = -0x3f3f3f3f;
70     j = 0;
71     for(i = 0;i < n; i++)
72     {
73         if(dpmax[i][0][n - 1] > maxx)
74         {
75             maxx = dpmax[i][0][n - 1];
76             j = 0;//因为当maxx更新后,以前的答案并不是最大值,所以我们应当重新记录
77             path[j++]=i + 1;//+1是因为从0开始
78         }
79         else if(dpmax[i][0][n - 1]==maxx)
80         path[j++] = i + 1;
81     }
82     printf("%d\n", maxx);
83     k = j;
84     for(j = 0;j <= k - 1; j++)
85     printf("%d ",path[j]);
86     return 0;
87 }
View Code

 

posted @ 2015-07-30 13:44  kiritoghy  阅读(212)  评论(0编辑  收藏  举报