P1005 矩阵取数游戏
Posted 范仁义
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
2 3 1 2 3 3 4 2
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 }
以上是关于P1005 矩阵取数游戏的主要内容,如果未能解决你的问题,请参考以下文章