Sephiroth's boring days!!!

Love just for you.

#

四塔问题

 

【描述】

“汉诺塔”,是一个众所周知的古老游戏。现在我们把问题稍微改变一下:如果一共有4根柱子,而不是3根,那么至少需要移动盘子多少次,才能把所有的盘子从第1根柱子移动到第4根柱子上呢?

为了编程方便,您只需要输出这个结果mod 10000的值。

【输入】

一个正整数n。(0<n<=50000)

【输出】

一个正整数,表示把n个盘子从第1根柱子移动到第4根柱子需要的最少移动次数mod 10000的值。

【样例输入】

15

【样例输出】

129

【分析】

弄出前几个数,发现规律。

f[1]=1,之后分别是加2个2,加3个4,加4个8,加5个16……

  1: #include <stdio.h>
  2: #define maxn 50010
  3: 
  4: int a,b;
  5: int k=1,t;
  6: long long j=1;
  7: int n;
  8: 
  9: int main()
 10: {
 11:     freopen("hnoi.in","r",stdin);
 12:     freopen("hnoi.out","w",stdout);
 13:     
 14:     scanf("%d",&n);
 15:     b=1;
 16:     for (int i=2;i<=n;++i)
 17:     {
 18:         a=b;
 19:         if (!t)
 20:         {
 21:             t=++k;
 22:             j*=2;
 23:             j%=10000;
 24:         }
 25:         b=(a+j)%10000;
 26:         --t;
 27:     }
 28:     printf("%d\n",b);
 29:     return 0;
 30: }
 31: 

posted @ 2010-09-02 11:27 Sephiroth Lee 阅读(244) | 评论 (0)编辑 收藏

动态规划-工业时代

【试题描述】

小FF的第一片矿区已经开始运作了, 他着手开展第二片矿区……

小FF的第二片矿区, 也是”NewBe_One“计划的核心部分, 因为在这片矿区里面有全宇宙最稀有的两种矿物,科学家称其为NEW矿和BE矿。

矿区是被划分成一个n*m的矩形区域。 小FF探明了每一小块区域里的NEW矿和BE矿的蕴藏量, 并且小FF还在矿区的北边和西边分别设置了NEW矿和BE矿的收集站。你的任务是设计一个管道运输系统,使得运送的NEW矿和BE矿的总量最多。

管道的型号有两种,一种是东西向,一种是南北向。在一个格子内你能建造一种管道,但丌能两种都建。如果两个同类型管道首位相接,它们就可以被连接起来。

另外这些矿物都十分丌稳定,因此它们在运送过程中都丌能拐弯。这就意味着如果某个格子上建有南北向管道,但是它北边的格子建有东西向管道,那么这根南北向管道内运送的任何东西都将丢失。迚一步地,运到NEW矿收集站的BE矿也会丢失,运到BE矿收集站的NEW矿也会丢失。

image

【输入格式】

第一行包含两个整数n和m,表示矿区大小。

以下n行,每行m个整数,其中第i行第j个整数G[ i , j ] 描述各个格子上的BE矿数量。接下来以类似的矩阵表示各个格子上的NEW矿数量。

【输出格式】

仅一个整数, 表示最多可以采集到的NEW矿和BE矿的总量。

【输入样例】

4 4

0 0 10 9

1 3 10 0

4 2 1 3

1 1 20 0

10 0 0 0

1 1 1 30

0 0 5 5

5 10 10 10

【输出样例】

98

【数据范围】

对于30%的数据: 0<= n,m <=100;

对于100%的数据: 0<= n, m <=1000;

0<= G[ i, j ] <=1000.

【分析】

每个点只有两种状态,放be的管道或者放new的管道。

  1: #include <stdio.h>
  2: #include <iostream>
  3: #define maxn 1010
  4: using namespace std;
  5: 
  6: int g[maxn][maxn][2];
  7: long long f[maxn][maxn][2];
  8: int ne[maxn][maxn],be[maxn][maxn];
  9: int n,m;
 10: 
 11: int main()
 12: {
 13:     freopen("industry.in","r",stdin);
 14:     freopen("industry.out","w",stdout);
 15:     
 16:     scanf("%d%d",&n,&m);
 17:     for (int i=1;i<=n;++i)
 18:         for (int j=1;j<=m;++j)
 19:             scanf("%d",&g[i][j][0]);
 20:     for (int i=1;i<=n;++i)
 21:         for (int j=1;j<=m;++j)
 22:             scanf("%d",&g[i][j][1]);
 23:     for (int i=1;i<=n;++i)
 24:         for (int j=1;j<=m;++j)
 25:         {
 26:             ne[i][j]=ne[i-1][j]+g[i][j][1];
 27:             be[i][j]=be[i][j-1]+g[i][j][0];
 28:         }
 29:     for (int i=1;i<=n;++i)
 30:         for (int j=1;j<=m;++j)
 31:         {
 32:             f[i][j][0]=be[i][j]+max(f[i-1][j][0],f[i-1][j][1]);
 33:             f[i][j][1]=ne[i][j]+max(f[i][j-1][1],f[i][j-1][0]);
 34:         }
 35:     printf("%lld\n",max(f[n][m][1],f[n][m][0]));
 36:     return 0;
 37: }
 38: 

posted @ 2010-09-02 07:24 Sephiroth Lee 阅读(244) | 评论 (0)编辑 收藏

动态规划-田忌赛马

 

【描述】

中国古代的历史故事“田忌赛马”是为大家所熟知的。话说齐王和田忌又要赛马了,他们各派出N匹马,每场比赛,输的一方将要给赢的一方200两黄金,如果是平局的话,双方都不必拿出钱。现在每匹马的速度值是固定而且已知的,而齐王出马也不管田忌的出马顺序。请问田忌该如何安排自己的马去对抗齐王的马,才能赢取最多的钱?

【输入】

第一行为一个正整数n (n <= 2000) ,表示双方马的数量。

第二行有N个整数表示田忌的马的速度。

第三行的N个整数为齐王的马的速度。

【输出】

仅有一行,为田忌赛马可能赢得的最多的钱,结果有可能为负。

【样例输入】

3

92 83 71

95 87 74

【样例输出】

200

【分析】

如果齐王的马是按速度排序之后,从高到低被派出的话,田忌一定是将他马按速度排序之后,从两头取马去和齐王的马比赛。

n设f[i,j]表示齐王按从强到弱的顺序出马和田忌进行了i场比赛之后,从“头”取了j匹较强的马,从“尾”取了i-j匹较弱的马,所能够得到的最大盈利。

n状态转移方程如下:

nF[I,j]=max{f[i-1,j]+g[n-(i-j)+1,i],f[i-1,j-1]+g[j,i]}

n其中g[i,j]表示田忌的马和齐王的马分别按照由强到弱的顺序排序之后,田忌的第i匹马和齐王的第j匹马赛跑所能取得的盈利,胜为200,输为-200,平为0。

  1: #include <stdio.h>
  2: #include <limits.h>
  3: #include <stdlib.h>
  4: #define maxn 1010
  5: 
  6: int a[maxn],b[maxn];
  7: int g[maxn][maxn];
  8: int f[2][maxn];
  9: int n,er;
 10: int ans;
 11: 
 12: int cmp(const void*a,const void*b)
 13: {
 14:     int c=*(int*)a,d=*(int*)b;
 15:     if (c<d) return 1;
 16:     if (c>d) return -1;
 17:     return 0;
 18: }
 19: 
 20: int main()
 21: {
 22:     scanf("%d",&n);
 23:     for (int i=1;i<=n;++i) scanf("%d",&b[i]);
 24:     for (int i=1;i<=n;++i) scanf("%d",&a[i]);
 25:     a[0]=b[0]=INT_MAX;
 26:     qsort(a,n+1,sizeof(int),cmp);
 27:     qsort(b,n+1,sizeof(int),cmp);
 28:     for (int i=1;i<=n;++i)
 29:         for (int j=1;j<=n;++j)
 30:             if (a[i]>b[j]) g[i][j]=-200;
 31:             else
 32:                 if (a[i]<b[j]) g[i][j]=200;
 33:     for (int i=1;i<=n;++i)
 34:     {
 35:         er^=1;
 36:         for (int j=0;j<=i;++j)
 37:         {
 38:             f[er][j]=f[er^1][j]+g[i][n-i+j+1];
 39:             if (j)
 40:                 if (f[er^1][j-1]+g[i][j]>f[er][j])
 41:                     f[er][j]=f[er^1][j-1]+g[i][j];
 42:         }
 43:     }
 44:     for (int i=0;i<=n;++i)
 45:         if (f[er][i]>ans)
 46:             ans=f[er][i];
 47:     printf("%d\n",ans);
 48:     return 0;
 49: }
 50: 

posted @ 2010-09-02 06:25 Sephiroth Lee 阅读(1773) | 评论 (0)编辑 收藏

“长沙一中学习”-day2

今天上午讲的是线性的动归。讲的例题有:

  1. 机器分配模型
  2. 楼梯问题
  3. 田忌赛马
  4. 最长公共子串

然后就是有关矩形的动态规划。如下:

  1. 滑雪
  2. 工业时代

还有区间类的:

  1. 凸多边形划分
  2. 最大乘积
  3. 石子合并(用到了四边形不等式)
  4. 数字游戏

然后有三道测试题:

  1. 四塔问题
  2. 关灯
  3. 任务安排

下午开始将树形的动态规划。

  1. 聚会的快乐
  2. 三色二叉树
  3. 皇宫看守
  4. 珠宝
  5. 符文之旅(最小与最大

没有写的题目以后会逐步完成。

posted @ 2010-09-01 21:54 Sephiroth Lee 阅读(103) | 评论 (0)编辑 收藏

树形动态规划-三色二叉树

【问题描述】

一棵二叉树可以按照如下规则表示成一个由0、1、2 组成的字符序列,我们称之为“二叉树序列S”:

2表示该树有两个子节点, 和分别表示其两个子树的二叉树序列

1表示该树有一个子节点, 为其子树的二叉树序列

0表示该树没有子节点

你的任务是要对一棵二叉树的节点进行染色。每个节点可以被染成红色、绿色或蓝色。并且,一个节点与其子节点的颜色必须不同,如果该节点有两个子节点,那么这两个子节点的颜色也必须不相同。给定一棵二叉树的二叉树序列,请求出这棵树中最多和最少有多少个点能够被染成绿色。

【输入文件】

输入文件名:TRO.IN

输入文件仅有一行,不超过10000 个字符,表示一个二叉树序列。

【输出文件】

输出文件名:TRO.OUT

输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被

染成绿色。

【样例输入】

1122002010

【样例输出】

5 2

【分析】

1.动归分析

拿最大来说。

每个节点的状态只有三种颜色,我们用f[i][0],f[i][1]分别代表第i个点染绿色和不然绿色的最多的点数。因为如果一个点不染绿色,那么他染另两种颜色是等价的。如此我们就得到了如下的动规方程:

  • 叶子:f[i][0]=1; f[i][1]=0;
  • 一个子节点:f[i][0]=f[子节点][1]; f[i][1]=max(f[子节点][0],f[子节点][1]);
  • 两个子节点:f[i][0]=f[左儿子][1]+f[右儿子][1]; f[i][1]=max(f[左儿子][1]+f[右儿子][0],f[左儿子][0]+f[右儿子][1]);

最后输出就是max(f[0][1],f[0][0])。

最小的和最大的相同。

2.树的确定

因为是一棵二叉树的前序遍历,那么对于一个有子节点的点来说,左儿子就是i+1。我们引进一个link[i],表示以i为根的子树最后一个点的标号,那么r[i]=link[l[i]]+1。

对于link[l],我们如此确定:

  • 叶子:link[l]=l;
  • 一个子节点:link[l]=link[l+1];
  • 两个子节点:link[l]=link[link[l+1]+1];

然后就是实现了。因为自己弄得还是不是很熟,打了两节课。

  1: #include <stdio.h>
  2: #include <string.h>
  3: #include <iostream>
  4: #define maxn 10010
  5: #define MAXINT 10000000
  6: using namespace std;
  7: 
  8: char s[maxn];
  9: int f[maxn][2];
 10: int link[maxn];
 11: int n;
 12: int l[maxn],r[maxn];
 13: 
 14: int _find(int x)
 15: {
 16:     if (link[x]) return link[x];
 17:     if (s[x]=='0') link[x]=x;
 18:     else
 19:         if (s[x]=='1') link[x]=_find(x+1);
 20:         else
 21:             link[x]=_find(_find(x+1)+1);
 22:     return link[x];
 23: }
 24: 
 25: void find1(int x)
 26: {
 27:     if (f[x][0]) return;
 28:     if (s[x]=='0')
 29:     {
 30:         f[x][0]=1;
 31:         f[x][1]=0;
 32:     }
 33:     else
 34:         if (s[x]=='1')
 35:         {
 36:             find1(l[x]);
 37:             f[x][0]=f[l[x]][1]+1;
 38:             f[x][1]=max(f[l[x]][1],f[l[x]][0]);
 39:         }
 40:         else
 41:         {
 42:             find1(l[x]);
 43:             find1(r[x]);
 44:             f[x][0]=f[l[x]][1]+f[r[x]][1]+1;
 45:             f[x][1]=max(f[l[x]][1]+f[r[x]][0],f[l[x]][0]+f[r[x]][1]);
 46:         }
 47: }
 48: 
 49: void find2(int x)
 50: {
 51:     if (f[x][0]<MAXINT) return;
 52:     if (s[x]=='0')
 53:     {
 54:         f[x][0]=1;
 55:         f[x][1]=0;
 56:     }
 57:     else
 58:         if (s[x]=='1')
 59:         {
 60:             find2(l[x]);
 61:             f[x][0]=f[l[x]][1]+1;
 62:             f[x][1]=min(f[l[x]][1],f[l[x]][0]);
 63:         }
 64:         else
 65:         {
 66:             find2(l[x]);
 67:             find2(r[x]);
 68:             f[x][0]=f[l[x]][1]+f[r[x]][1]+1;
 69:             f[x][1]=min(f[l[x]][1]+f[r[x]][0],f[l[x]][0]+f[r[x]][1]);
 70:         }
 71: }
 72: 
 73: int main()
 74: {
 75:     freopen("tro.in","r",stdin);
 76:     freopen("tro.out","w",stdout);
 77:     
 78:     scanf("%s",s);
 79:     n=strlen(s);
 80:     _find(0);
 81:     for (int i=0;i<n;++i)
 82:     {
 83:         l[i]=i+1;
 84:         r[i]=link[l[i]]+1;
 85:     }
 86:     find1(0);
 87:     printf("%d ",max(f[0][0],f[0][1]));
 88:     for (int i=0;i<n;++i)
 89:         f[i][0]=f[i][1]=MAXINT;
 90:     find2(0);
 91:     printf("%d\n",min(f[0][0],f[0][1]));
 92:     return 0;
 93: }
 94: 

posted @ 2010-09-01 21:41 Sephiroth Lee 阅读(731) | 评论 (0)编辑 收藏

区间类动态规划-数字游戏

题目网上都可以找到。

注意初始化s[i][j]的时候要加上100000而不是10!!!我傻叉子了= =

  1: #include <stdio.h>
  2: #define MAXINT 10000000
  3: #define maxn 200
  4: 
  5: int f[maxn][maxn][maxn][2];//0 max|||| 1 min
  6: int s[maxn][maxn];
  7: int a[maxn];
  8: int n,m;
  9: int maxans,minans=MAXINT;
 10: 
 11: void find(int x,int y,int t)
 12: {
 13:     if (f[x][y][t][0]) return;
 14:     if (t==1)
 15:     {
 16:         f[x][y][1][0]=f[x][y][1][1]=s[x][y];
 17:         return;
 18:     }
 19:     for (int k=x+t-1-1;k<y;++k)
 20:     {
 21:         find(x,k,t-1);
 22:         if (f[x][k][t-1][1]*s[k+1][y]<f[x][y][t][1]) f[x][y][t][1]=f[x][k][t-1][1]*s[k+1][y];
 23:         if (f[x][k][t-1][0]*s[k+1][y]>f[x][y][t][0]) f[x][y][t][0]=f[x][k][t-1][0]*s[k+1][y];
 24:     }
 25: }
 26: 
 27: int main()
 28: {
 29:     freopen("game.in","r",stdin);
 30:     freopen("game.out","w",stdout);
 31:     
 32:     scanf("%d%d",&n,&m);
 33:     for (int i=1;i<=n;++i)
 34:     {
 35:         scanf("%d",&a[i]);
 36:         a[i+n]=a[i];
 37:     }
 38:     for (int i=1;i<=2*n;++i)
 39:         for (int j=i;j<=2*n;++j)
 40:             for (int k=1;k<=m;++k)
 41:                 f[i][j][k][1]=MAXINT;
 42:     for (int i=1;i<=2*n;++i)
 43:         for (int j=i;j<=2*n;++j)
 44:             s[i][j]=(s[i][j-1]+a[j]+100000)%10;
 45:     for (int i=1;i<=n;++i) find(i,i+n-1,m);
 46:     for (int i=1;i<=n;++i)
 47:     {
 48:         if (f[i][i+n-1][m][0]>maxans) maxans=f[i][i+n-1][m][0];
 49:         if (f[i][i+n-1][m][1]<minans) minans=f[i][i+n-1][m][1];
 50:     }
 51:     printf("%d\n%d\n",minans,maxans);
 52:     return 0;
 53: }
 54: 

posted @ 2010-09-01 21:40 Sephiroth Lee 阅读(310) | 评论 (0)编辑 收藏

数学问题-Black and White

【题目描述】

寻找一个由n个整数组成的数列,其中任意连续p个整数之和为正,任意连续q个整数之和为负。若不存在这样的整数数列,则输出NO,否则输出其中一个数列。

【输入】

对于每个测试点将给你M组数据,要求你对于每组数据,判断是否存在这样的整数数列。

输入的第一行是一个正整数M,(1<=N<=10000),接下来的M行对应M组数据,每行有三个正整数N、P、Q(1<=n,p,q<=10^8)。

【输出】

输出数据共N行,每行为yes或者no,如果第I组数据有解,则在第I行输出yes,否则输出no

【输入输出示例】

输入(sequence.in) 输出(sequence.out)
2
1 1 9
10 2 4
yes
no

【评分标准】

对于每个测试点,如果你能够在1S内通过每组数据,你将得到这个测试点的分数,否则,这个测试点你只能得0分。

【分析】

原题目是要求输出一种可能的解,如果没有解就输出-1。这样的话就要用到差分约束。

现在的话,只需要一个公式。如果有解,应满足:n<=q+p-gcd(p,q)-1。

  1: #include <stdio.h>
  2: #include <iostream>
  3: using namespace std;
  4: 
  5: int n,m,p,q;
  6: 
  7: int gcd(int a,int b)
  8: {
  9:     if (a<b) swap(a,b);
 10:     int t;
 11:     while (b!=0)
 12:     {
 13:         t=a;
 14:         a=b;
 15:         b=t%a;
 16:     }
 17:     return a;
 18: }
 19: 
 20: int main()
 21: {
 22:     freopen("sequence.in","r",stdin);
 23:     freopen("sequence.out","w",stdout);
 24:     
 25:     scanf("%d",&m);
 26:     for (int i=0;i<m;++i)
 27:     {
 28:         scanf("%d%d%d",&n,&p,&q);
 29:         if (n<=p+q+gcd(p,q)-1) printf("YES\n");
 30:         else printf("NO\n");
 31:     }
 32:     return 0;
 33: }
 34: 

下面是我写的查分约束。

  1: #include <stdio.h>
  2: #define MAXINT 1000000
  3: #define maxn 1010
  4: 
  5: struct ss
  6: {
  7:     int x,y,dis;
  8: } l[10000];
  9: 
 10: int s[maxn];
 11: int a[maxn];
 12: int d[maxn];
 13: int n,q,p,tot;
 14: 
 15: int main()
 16: {
 17:     scanf("%d%d%d",&n,&p,&q);
 18:     for (int i=0;i<=n;++i)
 19:         if (i+p>n) break;
 20:         else
 21:         {
 22:             l[++tot].x=i+p;
 23:             l[tot].y=i;
 24:             l[tot].dis=-1;
 25:         }
 26:     for (int i=0;i<=n;++i)
 27:         if (i+q>n) break;
 28:         else
 29:         {
 30:             l[++tot].x=i;
 31:             l[tot].y=i+q;
 32:             l[tot].dis=-1;
 33:         }
 34:     for (int i=1;i<=n;++i)
 35:     {
 36:         for (int j=1;j<=tot;++j)
 37:             if (d[l[j].y]>d[l[j].x]+l[j].dis)
 38:                 d[l[j].y]=d[l[j].x]+l[j].dis;
 39:         for (int j=1;j<=tot;++j)
 40:             if (d[l[j].y]>d[l[j].x]+l[j].dis)
 41:             {
 42:                 printf("-1\n");
 43:                 return 0;
 44:             }
 45:     }
 46:     for (int i=0;i<=n;++i)
 47:         s[i]=d[i];
 48:     for (int i=1;i<=n;++i) printf("%d\n",s[i]-s[i-1]);
 49:     return 0;
 50: }
 51: 

posted @ 2010-09-01 07:00 Sephiroth Lee 阅读(132) | 评论 (0)编辑 收藏

“长沙一中学习”-day1

今天上午从东区搬东西到西区。11点都收拾完了,然后到水房泼了一个小时的水。

下午两点多的时候曹老师开始讲课。

今天的课程是两个内容:全面分析试题,动态规划。

曹老师拿他给自己的学生布置的任务做例子,大概的说了一下从一个题目的模型到完整的题目的过程。首先曹老师给了4道题目,都只是大概的描述。然后将每个条件定严谨。确定输入输出的格式。分析可以用什么算法,每种算法的时间复杂度以及可以通过的数据范围。根据算法定出数据,写出标程。曹老师说他们的学生每个人通过自己的分析,做出10个数据,然后大概100多个测试点来测试每个人写的程序。

以下是4道题目。第二题有些瓶颈,一会再发。

  1. 动态规划-走迷宫问题
  2. 空缺
  3. 贪心-买彩票
  4. 数学问题-Black and White

posted @ 2010-08-31 20:09 Sephiroth Lee 阅读(101) | 评论 (0)编辑 收藏

数学问题-Black and White

【题目描述】

寻找一个由n个整数组成的数列,其中任意连续p个整数之和为正,任意连续q个整数之和为负。若不存在这样的整数数列,则输出NO,否则输出其中一个数列。

【输入】

对于每个测试点将给你M组数据,要求你对于每组数据,判断是否存在这样的整数数列。

输入的第一行是一个正整数M,(1<=N<=10000),接下来的M行对应M组数据,每行有三个正整数N、P、Q(1<=n,p,q<=10^8)。

【输出】

输出数据共N行,每行为yes或者no,如果第I组数据有解,则在第I行输出yes,否则输出no

【输入输出示例】

输入(sequence.in) 输出(sequence.out)
2
1 1 9
10 2 4
yes
no

【评分标准】

对于每个测试点,如果你能够在1S内通过每组数据,你将得到这个测试点的分数,否则,这个测试点你只能得0分。

【分析】

原题目是要求输出一种可能的解,如果没有解就输出-1。这样的话就要用到差分约束。

现在的话,只需要一个公式。如果有解,应满足:n<=q+p+gcd(p,q)-1。

  1: #include <stdio.h>
  2: #include <iostream>
  3: using namespace std;
  4: 
  5: int n,m,p,q;
  6: 
  7: int gcd(int a,int b)
  8: {
  9:     if (a<b) swap(a,b);
 10:     int t;
 11:     while (b!=0)
 12:     {
 13:         t=a;
 14:         a=b;
 15:         b=t%a;
 16:     }
 17:     return a;
 18: }
 19: 
 20: int main()
 21: {
 22:     freopen("sequence.in","r",stdin);
 23:     freopen("sequence.out","w",stdout);
 24:     
 25:     scanf("%d",&m);
 26:     for (int i=0;i<m;++i)
 27:     {
 28:         scanf("%d%d%d",&n,&p,&q);
 29:         if (n<=p+q+gcd(p,q)-1) printf("YES\n");
 30:         else printf("NO\n");
 31:     }
 32:     return 0;
 33: }
 34: 

posted @ 2010-08-31 19:59 Sephiroth Lee 阅读(125) | 评论 (0)编辑 收藏

贪心-买彩票

【问题描述】

电视里面正放着“抽百万大奖,赢幸福生活”的宣传广告,bird看后也想去试试手气,当然,作为经济学院的高材生,他可不屑只是单纯的去碰运气。经过他的一番分析,发现,商家在彩票里面做了手脚,使得每个抽奖点的中奖概率不是完全一样的,而且随着时间的变化而变化,不过这种变化是有规律的。对于第I个抽奖点,最开始的中奖概率是百万分之Pi,以后每抽一张彩票后都要重新排队,花费的时间是T分钟,每抽一次减少的概率为Di。

由于可怜的bird还有一大堆的作业没做,他只能抽出H个小时去买彩票。由于抽奖地点都在一路公共汽车的线路上,所以怕麻烦的bird决定按车站顺序抽奖,当然,bird可以从任意一站开始抽奖,对于经过的抽奖点可以买彩票,也可以不买。假设从第I个抽奖点到第I+1个抽奖点需要做Ci分钟的汽车。

Bird希望能在有限的H个小时内获得最好的运气——即抽奖的概率和最大。

[输入] 输入文件名:(tickt.in)

第一行为一个整数n,表示抽奖点的个数,1<=n<=200

第二行是两个整数H和T,1<=H<=10,1<=T<=60。

接下来的n行,每行3个整数,分别是Pi,Di,Ci(Cn=0)。1<=Pi<=10000,Di<=Pi,1<=Ci<=600。

[输出] 输出文件名:(tickt.out)

文件仅有一行,为一个整数,即抽奖概率和的最大值。

【输入输出样例】

tickt.in tickt.out

2

1 20

200 100 10

300 200 0

500

【样例说明】

首先,bird从1号开始抽奖,花费20分钟,得到概率200,然后坐车到2号,花费10分钟,再花20分钟得到概率300,概率和是500,花费50分钟。

【评分标准】

对于每个测试点,如果你能够在规定的时间内通过每组数据,你将得到这个测试点的分数,否则,这个测试点你只能得0分。

【分析】

由CEOI的钓鱼改编,具体可以看《算法艺术与信息学竞赛》P13。

  1: #include <stdio.h>
  2: #include <iostream>
  3: #define maxn 210
  4: using namespace std;
  5: 
  6: int b[maxn][maxn];
  7: int p[maxn],d[maxn],c[maxn];
  8: int h,t,tot;
  9: struct ss
 10: {
 11:     int pi,di;
 12: } hp[maxn];
 13: int remain,ans,teans,n;
 14: 
 15: void down(int x)
 16: {
 17:     int te=2*x;
 18:     while (te<=tot)
 19:     {
 20:         if ((te+1<=tot)&&(hp[te].pi<hp[te+1].pi)) ++te;
 21:         if (hp[x].pi>hp[te].pi) break;
 22:         swap(hp[x],hp[te]);
 23:         x=te;
 24:         te=x*2;
 25:     }
 26: }
 27: 
 28: int main()
 29: {
 30:     freopen("ticket.in","r",stdin);
 31:     freopen("ticket.out","w",stdout);
 32:     
 33:     scanf("%d%d%d",&n,&h,&t);
 34:     h*=60;
 35:     for (int i=1;i<=n;++i) scanf("%d%d%d",&p[i],&d[i],&c[i]);
 36:     for (int i=1;i<=n;++i)
 37:         for (int j=i+1;j<=n;++j)
 38:             b[i][j]=b[i][j-1]+c[j-1];
 39:     for (int i=1;i<=n;++i)
 40:         for (int j=n;j>=i;--j)
 41:         {
 42:             teans=0;
 43:             remain=h-b[i][j];
 44:             memset(hp,0,sizeof(hp));
 45:             for (int k=1;k<=j-i+1;++k)
 46:             {
 47:                 hp[k].pi=p[i+k-1];
 48:                 hp[k].di=d[i+k-1];
 49:             }
 50:             tot=j-i+1;
 51:             for (int k=j-i+1;k>=1;--k) down(k);
 52:             while ((remain>=t)&&(hp[1].pi>0))
 53:             {
 54:                 teans+=hp[1].pi;
 55:                 hp[1].pi-=hp[1].di;
 56:                 remain-=t;
 57:                 down(1);
 58:             }
 59:             if (teans>ans) ans=teans;
 60:         }
 61:     printf("%d\n",ans);
 62:     return 0;
 63: }
 64: 

posted @ 2010-08-31 19:55 Sephiroth Lee 阅读(294) | 评论 (0)编辑 收藏

仅列出标题
共5页: 1 2 3 4 5 
free counters