关闭

NOIP2007 提高组 复赛 game 矩阵取数游戏

标签: NOIP提高组复赛
373人阅读 评论(0) 收藏 举报
分类:

NOIP2007 提高组 复赛 game 矩阵取数游戏

1.审题,弄懂样例。

2 3
1 2 3
3 4 2
取数如下:第1次1 2;第2次2 3;第3次3 4。

求和如下:1*2+2*2+2*4+3*4+3*8+4*8=82

感觉是贪心算法,但又感觉,贪心算法很可能只能得40分。存在反例,中间的数特别小,靠近行首行尾的数特别大。

2.动态规划,关键是找状态,以及状态转移方程,试试。

3.翻看他人做法,https://wenku.baidu.com/view/9db8950190c69ec3d5bb750c.html该篇写得不错,摘抄如下:

分析:此题为区间动归,做了田忌赛马后,此题的动态转移一点也不难,
f【i,j】表示区间(i,j)所能取得的最大值,取数时必取i或j
所以,转移方程式为f【i,j】=max(f【i+1,j】+a【i】,f【i,j-1】+a【j】)*2
边界为f【i,i】=a【i】*2
此题要用高精度,可以只写加法,把乘以二看做两个相加。还有一个高精度比较大小,为了不超时可把进制设为10000或更大。
注意输出的时候要进行补位。


4.http://blog.csdn.net/kingzone_2008/article/details/12589993该篇代码长度比较短,适合研究。

5.

http://www.cnblogs.com/Neptune-/p/5546711.html对上文有进一步的解释:

需要注意的地方:
  1.M和N给的范围略坑啊,2^80只有悄悄不说话了,所以直接上了100000的压位,感觉比高精好使多了
  2.2的次方多次用到,所以预先处理出来待用

6.//NOIP2007 提高组 复赛 game 矩阵取数游戏
//该题搁置有些久了,今天重新拿起进行处理2017-8-23
//同以往,弄明白样例,还是比较重要的。
//样例1,解析如下:
//第一行 1*2^1+2*2^2+3*2^3=34
//第二行 2*2^1+3*2^2+4*2^3=48
//最大得分 34+48=82
//由上述样例可得思路,每次取出该行,行首或行尾的最小值。
//上述思路,属贪心算法,估计只能过30%的数据,试试看。提交,测试点1,3AC 测试点2,4-10WA
//理解贪心算法为什么错,关键是找一个反例。
//搜索网络,发现一个比较好的贪心的反例http://blog.sina.com.cn/s/blog_5ef211b10100cr25.html
//样例2
//输入:
//1 4
//4 5 0 5


//输出:
//122
//样例2分析如下:
 

//样例2动态规划,手动模拟如下:

f[1][4]=max(f[2][4]+a[1],f[1][3]+a[4])*2;

f[2][4]=max(f[3][4]+a[2],f[2][3]+a[4])*2;

f[1][3]=max(f[2][3]+a[1],f[1][2]+a[3])*2;

f[3][4]=max(f[4][4]+a[3],f[3][3]+a[4])*2;

f[2][3]=max(f[3][3]+a[2],f[2][2]+a[3])*2;

f[1][2]=max(f[2][2]+a[1],f[1][1]+a[2])*2;

f[1][1]=a[1]*2;

f[2][2]=a[2]*2;

f[3][3]=a[3]*2;

f[4][4]=a[4]*2;

计算如下:

f[1][1]=a[1]*2; f[1][1]=8

f[2][2]=a[2]*2; f[2][2]=10

f[3][3]=a[3]*2; f[3][3]=0

f[4][4]=a[4]*2; f[4][4]=10


f[1][2]=max(f[2][2]+a[1],f[1][1]+a[2])*2; f[1][2]=max(14,13)*2=28

f[2][3]=max(f[3][3]+a[2],f[2][2]+a[3])*2; f[2][3]=max(5,10)*2=20

f[3][4]=max(f[4][4]+a[3],f[3][3]+a[4])*2; f[3][4]=max(10,5)*2=20


f[1][3]=max(f[2][3]+a[1],f[1][2]+a[3])*2; f[1][3]=max(24,28)*2=56

f[2][4]=max(f[3][4]+a[2],f[2][3]+a[4])*2; f[2][4]=max(25,25)*2=50
f[1][4]=max(f[2][4]+a[1],f[1][3]+a[4])*2; f[1][4]=max(50,56)*2=122

至此,应该可以说,掌握了区间动态规划。

//接下来,采用非高精度算法,进行动态规划,估计能拿60分。

//高精度算法,动态规划,提交,测试点2-10 WA 采用之前编好的非高精度算法,与当前程序,进行数据对比
//查了整整两天,程序的最大问题找到,memset(x,0,30*sizeof(int));//13 该函数的问题查了整整两天,在函数内传入的是x的收地址,x元素的个数在该函数体内未知,故函数体内memset要慎用memset(x,0,sizeof(x)); 4 漏了该句 初始化 
//提交AC,2017-8-26 终于AC,虽然代码写得很乱,但正是宣告,贪心,动态规划,高精度算法,上了一个新台阶,有独立完成的能力。 

总结:考试时,提交程序时,为了保证得分,非高精度算法更好,程序简单,不容易错,通常都能得到60分以上。

附上动态规划,高精度算法,AC代码。
#include <stdio.h>
#include <string.h>
int a[85][85];
int f[85][85][30],z1[30],z2[30],ans[30];//4 改进写法 z1[85][85][30],z2[85][85][30]
void add1(int *x,int y,int *z){//pass //x+y=z 每个元素表示4位,x[][][0]表示数据长度 
    int i; 
    memset(x,0,30*sizeof(int));//13 该函数的问题查了整整两天,在函数内传入的是x的收地址,x元素的个数在该函数体内为止,故函数体内memset要慎用memset(x,0,sizeof(x)); 4 漏了该句 初始化
    for(i=z[0];i>=0;i--)//12漏了两句 
        x[i]=z[i]; 
    x[1]+=y;//10 x[i]=z[i]+y;此句原来写在for循环内部 
    for(i=1;i<=z[0];i++){
        x[i+1]+=x[i]/10000;//9 此处写成 x[i+1]+=z[i]/10000; 查了好久好久 
        x[i]%=10000;
    }
    if(x[i])//5 此处写成 if(z[s][e][i]) 程序改了后,需要修改的地方很多,牵一发动全身 
        x[0]=z[0]+1;//2 低级错误,查了有点久,z[s][e][0]=x[s][e][0]++;x[s][e][0]先赋值,再自加
}
void add2(int *x,int *y){
    int i,len;
    x[0]=x[0]>y[0]?x[0]:y[0];//6  此处写成 ans[0]=ans[0]>y[s][e][0]?ans[0]:y[s][e][0];
    len=x[0]>y[0]?y[0]:x[0];//取小的
    for(i=1;i<=len;i++)//12漏了两句 
        x[i]+=y[i]; 
    for(i=1;i<=x[0];i++){
        x[i+1]+=x[i]/10000;//6 此处写成  ans[i+1]+=ans[i]/10000;
        x[i]%=10000;//6 此处写成  ans[i]%=10000;
    }
    if(x[i])//6 此处写成  if(ans[i])
        x[0]=x[0]+1;//6 此处写成 ans[0]=y[s][e][0]+1;2 低级错误,查了有点久,ans[0]=y[s][e][0]++;y[s][e][0]先赋值,再自加     
}
void mul(int *x,int y,int *z){//x+y=z 每个元素表示4位,x[][][0]表示数据长度 
    int i; 
    z[0]=x[0];//1 漏了该句
    for(i=1;i<=x[0];i++)//11 漏了两句,对乘法运算理解不深刻 
        z[i]=x[i]*y; 
    for(i=1;i<=x[0];i++){
        z[i+1]+=z[i]/10000;
        z[i]%=10000;
    }
    if(z[i])
        z[0]=x[0]+1;//2 低级错误,查了有点久,z[s2][e2][0]=x[s1][e1][0]++; x[s1][e1][0]先赋值,再自加     
}
int cmp(int *x,int *y){//x>y 1 x<y -1 x=y 0
    int i;
    if(x[0]>y[0])return 1;
    else if(x[0]<y[0])return -1;
    else{
        for(i=x[0];i>=1;i--)
            if(x[i]>y[i])
                return 1;
            else if(x[i]<y[i])
                return -1;
        return 0;
    }
}
int main(){
    int i,j,n,m,s,e,k,p;
    memset(f,0,sizeof(f));
    memset(ans,0,sizeof(ans));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)//1 此处写成 for(j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    for(i=1;i<=n;i++){
        memset(f,0,sizeof(f));//8 漏了初始化 
        for(k=1;k<=m;k++)
            f[k][k][0]=1,f[k][k][1]=a[i][k]*2;
        for(k=1;k<=m;k++)
            for(j=1;j<=m;j++)
                if(j+k<=m){
                    add1(z1,a[i][j],f[j+1][j+k]);
                    add1(z2,a[i][j+k],f[j][j+k-1]);
                    if(cmp(z1,z2)==1)
                        mul(z1,2,f[j][j+k]);
                    else
                        mul(z2,2,f[j][j+k]);
                }else
                    break;
        add2(ans,f[1][m]);
    }
    printf("%d",ans[ans[0]]);
    for(i=ans[0]-1;i>=1;i--)
        printf("%04d",ans[i]);//3  printf("%05d",ans[i]); 低级错误 10000 四位即可进位 
    return 0;
}   


//非高精度,动态规划 得分60分 测试点7-10WA 如果是考试,这个得分,应该比较满意了。
#include <stdio.h>
int a[85][85];
long long f[85][85];
long long max(long long a,long long b){
    return a>b?a:b;
}
int main(){
    int i,j,n,m,s,e,k;
    long long ans=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)//1 此处写成 for(j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    for(i=1;i<=n;i++){
        for(k=1;k<=m;k++)
            f[k][k]=a[i][k]*2;
        for(k=1;k<=m;k++)
            for(j=1;j<=m;j++)
                if(j+k<=m){
                    f[j][j+k]=max(f[j+1][j+k]+a[i][j],f[j][j+k-1]+a[i][j+k])*2;
                }else
                    break;
        ans+=f[1][m];
    }
    printf("%lld\n",ans);
    return 0;
}   


//附上贪心算法,得分20 

#include <stdio.h>
int a[85][85];
long long mul(int k){
    long long ret=1,i;
    for(i=1;i<=k;i++)
        ret*=2;
    return ret;    
}
int main(){
    int i,j,n,m,s,e,k;
    long long ans=0;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)//1 此处写成 for(j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    for(i=1;i<=n;i++){
        s=1,e=m,k=0;
        while(s<=e){
            k++;
            if(a[i][s]<a[i][e]){
                ans+=a[i][s]*mul(k);
                s++;
            }
            else{
                ans+=a[i][e]*mul(k);
                e--;
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}   


0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

NOIP2007矩阵取数游戏

题目来源:https://www.luogu.org/problem/show?pid=1005 dp并不难,f[i][j]表示从i到j的最大得分,f[i][j]=max(f[i+1][j]+a[...
  • moon_sky1999
  • moon_sky1999
  • 2016-11-05 20:41
  • 928

wikioi 1166 矩阵取数游戏(2007年NOIP全国联赛提高组)

题目描述 Description 【问题描述】 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数。游戏规则如下: 1. 每次取数...
  • kingzone_2008
  • kingzone_2008
  • 2013-10-11 01:07
  • 6507

wikioi 1166 矩阵取数游戏(2007年NOIP全国联赛提高组)

题目描述 Description 【问题描述】 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数。游戏规则如下: 1. 每次取数...
  • kingzone_2008
  • kingzone_2008
  • 2013-10-11 01:07
  • 6507

矩阵取数游戏

题目描述 Description 【问题描述】 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数。游戏规则如下: 1. 每次取数时须从每行各...
  • sinat_34943123
  • sinat_34943123
  • 2016-09-10 16:44
  • 1186

【日常学习】【区间DP+高精】codevs1166 矩阵取数游戏题解

题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小。 先上题目 题目描述 Description 【问题描述】 帅帅经常跟同学玩...
  • ametake
  • ametake
  • 2015-08-14 18:11
  • 3282

NOIP2000提高组 4.方格取数 C语言题解

问题描述:                       设有N*N的方格图(N...
  • u012525492
  • u012525492
  • 2013-10-26 10:14
  • 589

矩阵取数游戏

这是一道NOIp07年的原题,题目本身并不难。 题目看上去很熟悉,第一次看完题目后往贪心的方面去想的,设计了两种贪心策略:1、每次从两端选取最小的数字;2、从后向前倒推,使最后一次取到的数字最大...
  • Enjoying_Science
  • Enjoying_Science
  • 2014-08-06 22:13
  • 843

NOIP2007提高组——矩阵取数游戏(game)

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有...
  • ouqingliang
  • ouqingliang
  • 2017-05-09 16:12
  • 513

NOIP2007提高组 矩阵取数

NOIP2007提高组 矩阵取数 题目描述     帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:     1.每次取数时须从每...
  • earnMoney
  • earnMoney
  • 2017-09-23 00:43
  • 57

NOIP2007 矩阵取数游戏

3. 矩阵取数游戏 (game.pas/c/cpp) 【问题描述】     帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n*m 的矩阵,矩阵中的每个元素 aij 均 为非负整数。游戏规...
  • hahalidaxin
  • hahalidaxin
  • 2016-03-30 17:22
  • 113
    个人资料
    • 访问:91550次
    • 积分:3227
    • 等级:
    • 排名:第11840名
    • 原创:235篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条