Examination 20170318

【那23个路口】

时间限制:1s

空间限制:32M

先说说现有的两种思路,第一个是动态规划,好像类似于传纸条那个题的多维做法,我不是很了解。第二种思路就是深度优先搜索,如果朴素暴搜的话是4^23种路进行比较,所以需要用到记忆化搜索。

记忆化搜索就是将你已经完成的步数用一个数组记录下来,当下一次需要完成时只需要调用空间里的数组即可。这是一种以空间换时间的方法。

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<cstring>

using namespace std;

int i,j,m,n,t,sx,sy;

long longmaxx,endd;//坑1:这里的结果必须是long long,//题目中只给出了每一个输入的元素//都是longint,但没有注明结果取值

int mo[4][2]={{0,1},{0,-1},{-1,0},{1,0}};

int a[301][301];

long longf[24][50][50];//这个题目比较特殊,鉴于题目要//求是23步以内,所以我们需要记//录以出发点为中心23*23的区域,//并记录某一步在某一个点的最大//权值。

int readd()

{

int aans=0;

char ch=getchar();

while(ch<'0'||ch>'9')

ch=getchar();

while(ch>='0'&&ch<='9')

{

   aans*=10;

   aans+=ch-'0';

   ch=getchar();

}

return aans;

//读入优化,注意处理负数,这里没有处理负数的原因是下面//的输入好像没有用读入优化

void dfs(int x,int nx,int ny,long long now,int zx,int zy)//解释一下变量的含义:x—已走步数

//nx&ny—当前位置的横纵坐标

//now—当前位置获得的最大权值,注意开long long

//zx&zy—我们所编辑的坐标位置(以出发点为原点)

{

if(a[nx][ny]>0||(nx==sx&&ny==sy))//可行性剪枝

{

now+=a[nx][ny];

if(f[x][zx][zy]<now||(nx==sx&&ny==sy))//记忆化

f[x][zx][zy]=now;

else return;                          //剪枝

if(x==23){maxx=max(maxx,now);return;}

dfs(x+1,mo[0][0]+nx,mo[0][1]+ny,now,mo[0][0]+zx,mo[0][1]+zy);

dfs(x+1,mo[1][0]+nx,mo[1][1]+ny,now,mo[1][0]+zx,mo[1][1]+zy);

dfs(x+1,mo[2][0]+nx,mo[2][1]+ny,now,mo[2][0]+zx,mo[2][1]+zy);

dfs(x+1,mo[3][0]+nx,mo[3][1]+ny,now,mo[3][0]+zx,mo[3][1]+zy);

 //四个方向大法师

    }

}

 

int main()

{

//freopen("corner.in","r",stdin);

//freopen("corner.out","w",stdout);

//freopen("corner2.in","r",stdin);//。。。

n=readd(),m=readd();

for(i=1;i<=m;i++)

for(j=1;j<=n;j++)

{

cin>>a[i][j];

if(!a[i][j])

sx=i,sy=j;

    }

dfs(0,sx,sy,0,25,25);//初始化

cout<<maxx;

}

【我们的可可西里】

这个题类似于八皇后问题,童鞋们都用了大法师,具体大法师的代码如下:

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<cstring>

using namespace std;

int i,j,m,n,t;

int l[1005];

 

int readd()

{

int aans=0;

char ch=getchar();

while(ch<'0'||ch>'9')

ch=getchar();

while(ch>='0'&&ch<='9')

{

   aans*=10;

   aans+=ch-'0';

   ch=getchar();

}

return aans;

}

//加了读入优化也无济于事

void dfs(int x)

{

if(x==n+1) {t++;return;}

for(int i=1;i<=n;i++)

{

   if(!l[i]&&i!=x)

   {

      l[i]=1;

      dfs(x+1);

      l[i]=0;

   }

}

}

 

int main()

{

//freopen("keke.in","r",stdin);

//freopen("keke.out","w",stdout);

n=readd();

dfs(1);              //DFS暴搜

cout<<t;

return 0;

}

显然这个题绝对不能这么做,因为一旦到了N=11的时候就已经1.04秒上下了,所以我们只能得30分。

然后通过打表我们发现规律:

对于a[i]这个数组,我们有a[i]=a[i-1]*(i-1)*(-1)^(i-1)

所以这个题就很容易了吗?不,我们来看看当N=100的时候这个数有多大吧:

34332795984163804765195977526776142032365783805375784983543400282685180793327632432791396429850988990237345920155783984828001486412574060553756854137069878601

显然unsigned long long都不行,所以就得用高精了,为了节省时间,我们发现总是一个高(低)精数乘以一个低精数,所以我们就可以压位,就是把低精压在一个位上去做。

如下代码:

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<cstring>

using namespace std;

int i,j,m,n;

int s1[10005];

int mm[10005];

long long b;

 

void mul(int y)

{

j=1;

while(j<=s1[0])

{

   mm[j]=s1[j]*y+b;//ѹλ

   b=mm[j]/10;

   mm[j]%=10;

   j++;

}

j--;

while(b)

{

   mm[j+1]+=b%10;

   b/=10;

   j++;

}

mm[0]=j;

}

 

int main()

{

s1[1]=1;

s1[0]=1;

cin>>n;

if(n==3)

cout<<2;

else

{for(i=4;i<=n+1;i++)

{

   mul((i-1));

   if(i%2==0)

   mm[1]--;

   else

   mm[1]++;

   int tem=1,x;

    while(mm[tem]>10)

    {

    x=mm[tem]/10;

    mm[tem]%=10;

    tem++;

    mm[tem]+=x;

   }

   for(j=1;j<=mm[0];j++)

   s1[j]=mm[j];

   s1[0]=mm[0];

}

for(i=s1[0];i>=1;i--)

cout<<s1[i];

}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值