2019.7.9 school alternating test (T 3 to be more complete)

 

T1_ dug mines (submission bomp.cpp )

Well recursive Dafa

 

answer

Recursive senior title

 

This problem is solved in accordance with the idea of ​​de-mining

Ray number on three adjacent grid and add up to exactly equal to the number of the intermediate grid

So when we first determine the lattice around the mine, and the rest will be it resolved

 

Note well established that when the first digital grid is 1, they can put mine on the first grid, it can also put mine on the second grid, both of which may be one kind of a solution, another species no solution

 

PS: Today the problem of cancer is, first of all condemn T1 data point 18: 211, the answer is not unique ah! ! !

 

Code

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

int n;
bool flag;
int pan[10010];
int ans[10010];

bool dtdfh()
{
    for(int i=2;i<=n;i++)
    {
        ANS [I + . 1 ] PAN = [I] -ans [I] -ans [I- . 1 ];
         IF (ANS [I + . 1 ] < 0 || ANS [I + . 1 ]> . 1 ) return  0 ; // Excess 
    } 
    
    IF (ANS [n-+ . 1 ]> 0 ) return  0 ;   // should have digital digital position 
    the else  return  . 1 ; 
    
} 

int main () 
{ 
    the freopen ( " bomp.in " , " R & lt " , stdin); 
    the freopen ( " bomp.out","w",stdout);
    
    n=read();
    for(int i=1;i<=n;i++)
    {
        pan[i]=read();
        if(pan[i]<0||pan[i]>3||(i==1&&pan[i]>2)||(i==n&&pan[i]>2))  //输入不合法 
        {
            printf("No answer\n");
            return 0;
        } 
    } 
       
    // first determine a first ah
    IF (PAN [ . 1 ] == 0 ) {ANS [ . 1 ] = ANS [ 2 ] = 0 ;}
     IF (PAN [ . 1 ] == . 1 ) ANS {[ . 1 ] = . 1 ; ANS [ 2 ] = 0 ;}
     IF (PAN [ . 1 ] == 2 ) {ANS [ . 1 ] = ANS [ 2 ] = . 1 ;} 
    
    In Flag = dtdfh ();   // recursive solving 
    IF (PAN [ . 1 ] == . 1 && In Flag == 0 ) 
    { 
        ans [1]=0;ans[2]=1;
        flag=dtdfh();
    }
    
    if(!flag)   //无解 
    {
        printf("No answer\n");
        return 0;
    }
    
    else
    {
        for(int i=1;i<=n;i++)
           printf("%d ",ans[i]);
    }
    
    return 0;
}

 

 

 

T2_ extreme value problem (submission mn.cpp)

Well play table Dafa

answer

I say this problem is to find the law to play table found Fibonacci columns QWQ

After playing table found m, n being not more than two adjacent maximum k Fibonacci

 

Positive Solutions of evidence Mingfei Bo Fibonacci , thanks to this big brother "  Send ephemera in the world, one of vague drop in the ocean  "

 

Prove it:

First, we see that the formula given in the title:

                        start:(n2-mn-m22=1

                       ----> : (m2+mn-n22=1

See separate out in parentheses: m 2 + n-Mn-

                                       m No 2 + MN-N + 2n 2 -2n 2 + MN-MN

                                   (m+n)2-2n2-mn

                                   (m+n)-n2-n2-mn

                                   (m+n)-(m+n)n - n2  

                      也就是:(n2-mn-m22  ---->   (m+n)-(m+n)n - n2  

        so,如果我们有一组解 (m,n),那么一定还存在一组解 (n,m+n),所以你发现这就构成了斐波那契数列!!!

        递推求解就好了!!!

 

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=1e6+10;
int k,m,n;
long long feibo[maxn]={1,1};

int main()
{
    freopen("mn.in","r",stdin);
    freopen("mn.out","w",stdout);
    k=read();
    
    for(int i=2;i<=45;i++)
    {
        feibo[i]=feibo[i-1]+feibo[i-2];
    }
    
    for(int i=1;i<=45;i++)
    {
        if(feibo[i]>k) {
            m=i-1;
            n=i-2;
            printf("%ld %ld\n",feibo[n],feibo[m]);
            return 0;
        }
    }
    
    return 0;
}

 

 

 

 T3_15数码问题(提交文件Puzzle15.cpp)

骗分大法好啊

题解

说人话:编程50步求解15数码

这题数据水,偏分最高60 

what is UVA???一个nice的oj

 

这个题目用到了神奇的 IDA* 算法(崩溃)

感谢百度找到一个大佬--恋恋恋恋吥舍--

链接: 原文:https://blog.csdn.net/baidu_30476939/article/details/53119195 

 

首先了解一下几个概念:

1.逆序对:在一个序列里,如果一个数后面的数比他小,那么他们两个构成一个逆序对

   有何用处??判断一下有无解:

           把初始矩阵从左到右,从上到下,展成一行,求它的逆序对 (显然目标矩阵的逆序对个数为0)

           于是这里用到一个定理:设初始状态0所在的行数为i,目标状态0所在的行数为j,两者之差的绝对值为k。若k为奇数,则初始矩阵与目标矩阵两个矩阵相应的逆序数的奇偶性相异才有解。若k为偶数,则两个矩阵的逆序数必须相同才有解。不是上述两种情况即为无解。通过初始判定就可以不用搜索就能直接否定无解情况。


转化到这个题上就是,K为奇数,矩阵逆序对数也应为奇数,K为偶数,矩阵逆序对数也应为偶数

 

2.曼哈顿距离:坐标系中两点  横坐标之差的绝对值+纵坐标的绝对值  之和

有何用处:预估最少步数,预估出来的步数一定是小于等于实际步数的

官方一点就是:求出初始矩阵与目标矩阵对应值得曼哈顿距离并求和(除去0)得到的值为评估值,写成函数即为评估函数。该值为从初始状态到目标状态所要经过的最小步数,实际步数只会大于等于该值。

 

算法介绍:

       这次使用的算法是IDA*。我们首先是用逆序数进行判定是否有解,有解才进行搜索。有解的话,则先得到评估函数的初始值,该值为最小步数,递归深度(步数)必然大于等于这个初始值limit。我们先按深度搜索寻遍该深度的所有情况,看是否能找到解,有解则该解是最优解。若没解,则将深度的限制条件limit加1,再次递归下一层深度的所有情况,有解即为最优解,无解则继续将深度限制条件limit加1,这样不停循环直到某个深度maxLevel,则放弃寻找,因为在maxLevel步中没有找到,继续找下去时间花销太高,故放弃寻找。这就是IDA*中ID的意思,迭代加深。其中,算法在递归中使用了当前递归深度level,用level+评估函数(当前状态到目标状态至少需要的步数)<=limit作为剪枝条件,不满足该条件的在该分支上肯定无解。这样我们就可以找到在maxLevel步以内的最优解。

 

 

代码

 

//15数码问题 
#include<iostream>
#include<cstdlib>
#include<cmath>
#define size 4
using namespace std;

int move[4][2]={{-1,0},{0,-1},{0,1},{1,0}};//上,左,右,下增量 
char op[4]={'U','L','R','D'};
int map[size][size],map2[size*size],limit,path[100];
//limit预估最少步数 
int flag,length;
//int goal_st[3][3]={{1,2,3},{4,5,6},{7,8,0}};//目标状态 
//goal存储目标位置,即0存在(3,3),1存在(0,0)... 
int goal[16][2]= {{3,3},{0,0},{0,1}, {0,2},
                  {0,3},{1,0},{1,1}, {1,2}, 
                  {1,3},{2,0},{2,1}, {2,2},
                  {2,3},{3,0},{3,1}, {3,2}};
                    
int h(int a[size*size])//求逆序数 ,判断有无解 
{
  int i,j,num,w,x,y; //w记录起点标号 
  num=0;  //逆序对数 
  for(i=0;i<size*size;i++) 
  {
    if(a[i]==0)
      w=i;
    for(j=i+1;j<size*size;j++)
    {
      if(a[i]>a[j])
        num++;
    }
  }
  
  x=w/size;  //起点横坐标 
  y=w%size;  //起点纵坐标 
  
  num+=abs(x-3)+abs(y-3);  //9102.9.7
  
  if(num%2==1)
    return 1;
  else
    return 0;
}

int manhattan(int a[][size])//计算曼哈顿距离,小等于实际总步数
{
  int i,j,cost=0;
  for(i=0;i<size;i++)
    for(j=0;j<size;j++)
    {
      int w=map[i][j];
      cost+=abs(i-goal[w][0])+abs(j-goal[w][1]);
    }
  return cost;
}

void swap(int*a,int*b)
{
  int tmp;
  tmp=*a;
  *a=*b;
  *b=tmp;
}

void dfs(int sx,int sy,int dep,int pre_move)//sx,sy是空格的位置
{
  int i,j,nx,ny;
  if(flag)
    return;
  int dv=manhattan(map);
  if(dep==limit)
  {
    if(dv==0)
    {
      flag=1;
      length=dep;
      return;
    }
    else
      return;
  }
  else if(dep<limit)
  {
    if(dv==0)
    {
      flag=1;
      length=dep;
      return;
    }
  }
  for(i=0;i<4;i++)//4个方向尝试 
  {
    if(i+pre_move==3&&dep>0)//不和上一次移动方向相反,对第二步以后而言
      continue;    
    nx=sx+move[i][0];
    ny=sy+move[i][1];
    if(0<=nx && nx<size && 0<=ny&&ny<size)//如果可以移动 
    {
       swap(&map[sx][sy],&map[nx][ny]);//交换两位置 
       int p=manhattan(map);
       if(p+dep<=limit&&!flag)
       {
          path[dep]=i;
         dfs(nx,ny,dep+1,i);
         if(flag)
           return;
       }
       swap(&map[sx][sy],&map[nx][ny]);
    }
  }
}

int main()
{
  freopen("Puzzle15.in","r",stdin);
  freopen("Puzzle15.out","w",stdout);  
  int i,j,k,l,m,n,sx,sy;
  char c,g;
  i=0;
  scanf("%d",&n);
  while(n--)  //n组数据 
  {
    flag=0;length=0;
    //flag判断有无解 
    
    memset(path,-1,sizeof(path));
    //路径存储数组,记录每一步的抉择,也就是最后要输出的答案
    //(数字代码,后边转化成字符串) 
    
    for(i=0;i<16;i++)
    {
      scanf("%d",&map2[i]); //读入15数码图 
      if(map2[i]==0)  //寻找0在哪里 
      { 
        map[i/size][i%size]=0;  //记录在图上的位置 
        sx=i/size;sy=i%size;    //记录起点的横纵坐标 
      }
      else
      {
        map[i/size][i%size]=map2[i];  //记录到图上 
      }
    }
    
    if(h(map2)==1)//该状态可达
    {
      limit=manhattan(map);
      while(!flag&&length<=50)//题中要求50步之内到达
      {
        dfs(sx,sy,0,0);
        if(!flag)
          limit++; //得到的是最小步数
      }
      if(flag)
      {
        for(i=0;i<length;i++)
          printf("%c",op[path[i]]);
        printf("\n");
      }
    }
    else if(!h(map2)||!flag)
      printf("This puzzle is not solvable.\n");
  }
  return 0;
}

 

 

-----在崩溃的边缘疯狂试探-----

 

Guess you like

Origin www.cnblogs.com/xiaoyezi-wink/p/11158629.html