P1005 矩阵取数游戏

P1005 矩阵取数游戏

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:

1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;

2.每次取走的各个元素只能是该元素所在行的行首或行尾;

3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);

4.游戏结束总得分为m次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入输出格式

输入格式:

输入文件game.in包括n+1行:

第1行为两个用空格隔开的整数n和m。

第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。

数据范围:

60%的数据满足:1<=n, m<=30,答案不超过10^16

100%的数据满足:1<=n, m<=80,0<=aij<=1000

输出格式:

输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。

输入输出样例

输入样例#1:

2 3
1 2 3
3 4 2

输出样例#1:

82

说明

NOIP 2007 提高第三题

思路:

1、贪心不行

贪心思路:

每次选取 两边都较小的值 让较小的值乘以低次幂 而较高的值留在后面 总之都要取完 而贪心只有20分

贪心错误实例:

如果有一组数据是4,3,10,1,1,1,1,1,1,1,1,5,5,5,5,9贪心就是错的,会先把5取完,然而应该先取1。

贪心错误原因:

前面的状态对后面有影响,这已经失去了贪心的条件。

2、动态规划

对于每一行,其实都是独立的,也就是每一行的最优值之和即为答案。而且看题目数据规模,要加高精度。

状态:

f[i][j]表示取下标为 i至j 的数字所能得到的最大得分

状态转移方程:

f[i][j]=2*max(f[i][j-1]+a[j],f[i+1][j]+a[i])

一个表示取头,一个表示取尾

这里相当于每到下一层都把上一层乘了2,越在内层,乘2的次数越多

60分代码

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int n,m,a[81];
 6 long long s,f[81][81];//f[j][k]j到k最大值
 7 int main()
 8 {
 9     scanf("%d%d",&n,&m);
10     for(int i=1;i<=n;i++)//i行数
11     {
12         for(int j=1;j<=m;j++)
13         {
14             scanf("%d",&a[j]);
15             f[j][j]=2*a[j];
16         }
17         for(int j=2;j<=m;j++)//区间长度
18             for(int k=1;k+j-1<=m;k++)//起点
19             {
20                 int g=k+j-1;//终点
21                 long long tmp=2*max(f[k+1][g]+a[k],f[k][g-1]+a[g]);
22                 f[k][g]=max(f[k][g],tmp);
23             }
24         s+=f[1][m];
25         memset(f,0,sizeof(f));
26     }
27     printf("%lld\n",s);
28     return 0;
29 }

100分代码

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 int n,m,a[81][101],s[101],tmp[4][101],f[81][81][101];//f[j][k]j到k最大值
  6 void init(int i,int aa[])//将i赋值给aa[]
  7 {
  8     if(i==0)
  9         aa[0]=1;
 10     while(i!=0)
 11     {
 12         aa[0]++;
 13         aa[aa[0]]=i%10;
 14         i/=10;
 15     }
 16 }
 17 void jin(int aa[])//进位操作
 18 {
 19     for(int i=1;i<=aa[0];i++)
 20     {
 21         aa[i+1]+=aa[i]/10;
 22         aa[i]%=10;
 23     }
 24     if(aa[aa[0]+1]!=0)
 25         aa[0]++;
 26     while(aa[aa[0]]/10!=0)
 27     {
 28         aa[aa[0]+1]+=aa[aa[0]]/10;
 29         aa[aa[0]]%=10;
 30         aa[0]++;
 31     }
 32     if(aa[aa[0]]==0&&aa[0]!=1)
 33         aa[0]--;
 34 }
 35 void jia1(int aa[],int bb[],int cc[])//将aa[]与bb[]相加,存入cc[]
 36 {
 37     for(int i=1;i<=aa[0]||i<=bb[0];i++)
 38         cc[i]=aa[i]+bb[i];
 39     cc[0]=max(bb[0],aa[0]);
 40     jin(cc);
 41 }
 42 void jia2(int aa[],int bb[])//将aa[]加bb[],存入bb[]
 43 {
 44     for(int i=1;i<=aa[0];i++)
 45         bb[i]+=aa[i];
 46     bb[0]=max(bb[0],aa[0]);
 47     jin(bb);
 48 }
 49 bool maxx(int aa[],int bb[])//返回aa[],bb[]中最大值
 50 {
 51     if(aa[0]>bb[0])
 52         return 1;
 53     else if(aa[0]<bb[0])
 54         return 0;
 55     else
 56         for(int i=aa[0];i>=1;i--)
 57         {
 58             if(aa[i]>bb[i])
 59                 return 1;
 60             else if(aa[i]<bb[i])
 61                 return 0;
 62         }
 63     return 0;
 64 }
 65 void fang(int aa[],int bb[])//将aa[]赋值给bb[]
 66 {
 67     for(int i=1;i<=aa[0];i++)
 68         bb[i]=aa[i];
 69     bb[0]=aa[0];
 70 }
 71 void dbbl(int aa[])//将aa[]翻倍
 72 {
 73     for(int i=1;i<=aa[0];i++)
 74         aa[i]*=2;
 75     jin(aa);
 76 }
 77 int main()
 78 {
 79     scanf("%d%d",&n,&m);
 80     for(int i=1;i<=n;i++)
 81     {
 82         int x;
 83         for(int j=1;j<=m;j++)
 84         {
 85             scanf("%d",&x);
 86             init(x,a[j]);
 87             init(2*x,f[j][j]);
 88         }
 89         for(int j=2;j<=m;j++)//区间长度
 90             for(int k=1;k+j-1<=m;k++)//起点
 91             {
 92                 int g=k+j-1;//终点
 93                 jia1(f[k+1][g],a[k],tmp[1]);
 94                 jia1(f[k][g-1],a[g],tmp[2]);
 95                 if(maxx(tmp[1],tmp[2]))
 96                     fang(tmp[1],tmp[3]);
 97                 else
 98                     fang(tmp[2],tmp[3]);
 99                 dbbl(tmp[3]);
100                 if(maxx(tmp[3],f[k][g]))
101                     fang(tmp[3],f[k][g]);
102                 memset(tmp,0,sizeof(tmp));
103             }
104         jia2(f[1][m],s);
105         memset(f,0,sizeof(f));
106         memset(a,0,sizeof(a));
107     }
108     for(int i=s[0];i>=1;i--)
109         printf("%d",s[i]);
110     printf("\n");
111     return 0;
112 }
时间: 2024-07-31 14:32:53

P1005 矩阵取数游戏的相关文章

洛谷P1005 矩阵取数游戏

P1005 矩阵取数游戏 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

P1005矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

洛谷 P1005 矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

18.7.27 luogu P1005 矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n \times mn×m 的矩阵,矩阵中的每个元素 a_{i,j}ai,j? 均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共 nn 个.经过 mm 次后取完矩阵内所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 \times 2^i×2i ,其中 ii 表示第 ii 次取数(从 11 开始编号): 游戏结束总得分为 mm

luogu P1005 矩阵取数游戏 区间DP

每一行是独立的,分开处理即可. dp[i][j]表示[i,j]这一段,取完的最大收益.转移很显然,dp[i][j] = max(dp[i + 1][j] + 2^(m - (j - l)) * mp[t][i],dp[i][j - 1] + 2^(m - (j - l)) * mp[t][j]) 不想写高精度,python水一发. 1 n,m = map(int,input().split()) 2 res = 0 3 mp = [[0 for i in range(0,80,1)] for i

[LuoguP1005]矩阵取数游戏 (DP+高精度)

题面 传送门:https://www.luogu.org/problemnew/show/P1005 Solution 我们可以先考虑贪心 我们每一次都选左右两边尽可能小的数,方便大的放在后面 听起来挺OK的 实则并不OK 反例: 3 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 如果贪心的话,我们会优先把右边那一串2先选了,再去选3和1 但是正确答案显然是先把3和1选了,再去选那一串2 既然贪心不成,我们可以考虑一下DP 然后我们考虑这样一个状态: f[i][j][k] 表示第i

矩阵取数游戏洛谷p1005

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

AC日记——矩阵取数游戏 洛谷 P1005

矩阵取数游戏 思路: dp+高精: 代码: #include <bits/stdc++.h> using namespace std; #define ll long long struct Int { int len; char ai[300]; Int() { len=1,ai[0]=0; } void Count(int pos) { len++; if(pos/10) Count(pos/10); } void operator=(int pos_) { int pos=pos_; l