zoukankan      html  css  js  c++  java
  • 【20190128】NOIP模拟赛190128

    T1 迷宫

    • 【题目描述】

      电脑游戏中有许多令人头疼的迷宫,会花费玩家相当多的时间,你通过秘笈获得了游戏迷宫的地图,你希望找到最短的一条走出迷宫的道路,并且想知道一共有多少条最短的道路,但是由于地图非常庞大,所以你不能在短时间找出这些道路,因此,你需要编写一个程序来找出这些最短的道路,并且统计一下一共有多少条这样的道路。

    例如,对于下图所示的迷宫:

     

     

     

    S

     

    X

    X

     

     

    X

    X

     

    E

     

     

     

      X表示障碍物,不可以通过,S表示迷宫的入口,E表示迷宫的出口。显然,从入口到出口至少需要走6步,而长度为6的道路一共有两条。

    • 【输入文件】

      输入文件maze.in,第一行是一个整数n(1 ≤n ≤ 25),表示迷宫是一个n×n的矩阵。以下n行每行有n个字符来描述地图,“.”表示可以通过,“X”表示不可以通过,“S”表示迷宫的入口,“E”表示迷宫的出口。(注意:所有的字母均为大写)。

    • 【输出文件】

      输出文件maze.out包括两行,第一行包含一个整数,表示从入口到出口走的最短距离。第二行包含一个整数,表示最短路径的条数,答案保证小于231

    • 【样例输入】

      4

      ...S

      .XX.

      .XX.

      E...

    • 【样例输出】

      6

      2

     1 /*
     2 id:gww
     3 language:
     4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 
     5 */
     6 #include<bits/stdc++.h>
     7 using namespace std;
     8 const int N=25+5;
     9 int n,sx,sy,ex,ey,f[900][N][N],cnt;
    10 char mp[N][N];
    11 int rd()
    12 {
    13     int x=0,w=0;char ch=0;
    14     while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    15     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    16     return w?-x:x;
    17 }
    18  
    19  
    20  
    21 int main()
    22 {
    23     memset(f,0,sizeof(f));
    24     n=rd();
    25     for(int i=0;i<n;i++)
    26     scanf("%s",mp[i]);
    27     for(int i=0;i<n;i++)
    28     for(int j=0;j<n;j++)
    29     {
    30         if(mp[i][j]=='S') sx=i,sy=j;
    31         if(mp[i][j]=='E') ex=i,ey=j;
    32         if(mp[i][j]=='X') cnt++;
    33     }
    34     f[0][sx][sy]=1;//初始化 
    35     for(int t=1;t<=n*n-cnt;t++)
    36     {
    37         if(f[t][ex][ey]) break;
    38         for(int i=0;i<n;i++)
    39         {
    40             for(int j=0;j<n;j++)
    41             {
    42                 if(mp[i][j]=='X'||!(f[t-1][i-1][j]+f[t-1][i+1][j]+f[t-1][i][j-1]+f[t-1][i][j+1])) continue;
    43                 f[t][i][j]=(f[t-1][i-1][j]+f[t-1][i+1][j]+f[t-1][i][j-1]+f[t-1][i][j+1]);
    44             }
    45         }
    46     }
    47     for(int t=0;t<=n*n-cnt;t++)
    48     if(f[t][ex][ey]) {printf("%d
    %d
    ",t,f[t][ex][ey]);exit(0);}
    49     return 0;
    50 }
    20昏 答案错误

    f[t][i][j]表示走t步到达(i,j) f[t][i][j]=f[t-1][i-1][j]+f[t-1][i+1][j]+f[t-1][i][j-1]+f[t-1][i][j+1](即(i,j)的上下左右位置的方法数和)

    但是不能直接f[t][i][j]=f[t-1][i-1][j]+f[t-1][i+1][j]+f[t-1][i][j-1]+f[t-1][i][j+1],要用像走迷宫一样的来枚举上一步,要判断上一步判断是否合法,否则会出现从(0,j)或者从(n+1,j)等非法位置到达终点,QAQ然后导致爆炸

     1 /*
     2 id:gww
     3 language:
     4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 
     5 */
     6 #include<bits/stdc++.h>
     7 using namespace std;
     8 const int N=25+5;
     9 int n,sx,sy,ex,ey,f[900][N][N],cnt;
    10 char mp[N][N];
    11 int dx[4]={0,0,1,-1};
    12 int dy[4]={1,-1,0,0};
    13 int rd()
    14 {
    15     int x=0,w=0;char ch=0;
    16     while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    17     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    18     return w?-x:x;
    19 }
    20 
    21 int main()
    22 {
    23     memset(f,0,sizeof(f));
    24     n=rd();
    25     for(int i=0;i<n;i++)
    26     scanf("%s",mp[i]);
    27     for(int i=0;i<n;i++)
    28     for(int j=0;j<n;j++)
    29     {
    30         if(mp[i][j]=='S') sx=i,sy=j;
    31         if(mp[i][j]=='E') ex=i,ey=j;
    32         if(mp[i][j]=='X') cnt++;
    33     }
    34     f[0][sx][sy]=1;//初始化 
    35     for(int t=1;t<=n*n-cnt;t++)
    36     {
    37         if(f[t][ex][ey]) break;
    38         for(int i=0;i<n;i++)
    39         for(int j=0;j<n;j++)
    40         if(mp[i][j]!='X')
    41         for(int k=0;k<4;k++)
    42         {
    43             int nx=i+dx[k],ny=j+dy[k];
    44             if(nx<0||ny<0||nx>n||ny>n||mp[nx][ny]=='X') continue;
    45             f[t][i][j]+=f[t-1][nx][ny];
    46         }
    47     }
    48     for(int t=0;t<=n*n-cnt;t++)
    49     if(f[t][ex][ey]) {printf("%d
    %d
    ",t,f[t][ex][ey]);exit(0);}
    50     return 0;
    51 }
    100昏 动规

    随机找的一个大佬的搜索

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,dis[30][30],sx,sy,ex,ey,ans[30][30],tu[30][30];
     4 struct node{
     5     int x,y;
     6 };
     7 int dx[4]={-1,0,0,1};
     8 int dy[4]={0,-1,1,0};
     9 queue<node>q;
    10 void bfs()
    11 {
    12     node a;
    13     a.x=sx;
    14     a.y=sy;
    15     q.push(a);
    16     dis[sx][sy]=0;
    17     ans[sx][sy]=1;
    18     while(!q.empty())
    19     {
    20         node u=q.front();
    21         q.pop();
    22         for(int i=0;i<4;i++)
    23         {
    24             int nx=u.x+dx[i];
    25             int ny=u.y+dy[i];
    26             if(!tu[nx][ny]) continue;
    27             if(dis[nx][ny]>dis[u.x][u.y]+1)
    28             {
    29                 dis[nx][ny]=dis[u.x][u.y]+1;
    30                 ans[nx][ny]=ans[u.x][u.y];
    31                 q.push(node{nx,ny});
    32             }
    33             else if(dis[nx][ny]==dis[u.x][u.y]+1)
    34                 ans[nx][ny]+=ans[u.x][u.y];
    35         }
    36     }
    37 }
    38  
    39 int main()
    40 {
    41     //freopen("in.txt","r",stdin);
    42     scanf("%d",&n);
    43     memset(dis,127,sizeof(dis));
    44     char QAQ;
    45     for(int i=1;i<=n;i++)
    46     {
    47         for(int j=1;j<=n;j++)
    48         {
    49             cin>>QAQ;
    50             if(QAQ=='S')
    51             tu[i][j]=1,sx=i,sy=j;
    52             if(QAQ=='E')
    53             tu[i][j]=1,ex=i,ey=j;
    54             if(QAQ=='.')
    55             tu[i][j]=1;
    56         }
    57     }
    58     bfs();
    59     printf("%d
    %d",dis[ex][ey],ans[ex][ey]);
    60     return 0;
    61 }
    100昏 搜索

    T2 最大数列

    • 题目描述

      有一个N项的数列a1, a2 ... aN (|ai| <=10000, 1 <= i <= N)。S定义为


      你的任务是求S的值,即为求一个序列的两个不相交连续子序列的最大和。

    • 【输入文件】

      输入文件sequence.in的第一行是一个整数N(2 <= N <= 100000),表示数列的项数。第二行有n个整数,用空格分隔,第i个整数Ai(|Ai| <=10000)是第i位数。

    • 【输出文件】

      输出文件sequence.out包括一行,这一行只包含一个整数,就是S。

    • 【样例输入】

      5 

      -5 9 -5 11 20

    • 【样例输出】

      40

    • 【数据规模】

      对于30%的数据,保证有n <= 80;

      对于70%的数据,保证有n <= 10000;

      对于全部的数据,保证有n <= 100000。

    先看一个求一个最大子列的求法 从左往右枚举(我感觉没什么好解释的)

    1 int sum=0,mi=0;
    2 for(int i=1;i<=n;i++)
    3 {
    4     sum+=a[i];
    5     ans=max(ans,sum-mi);
    6     mi=min(mi,sum);
    7 }

    然后两个子列不相交,我们就先从左往右求出左区间的最大子列 然后再从右往左求出右区间的最大子列 因为不相交 就加上f[i-1](配合下面代码食用)

     1 /*
     2 id:gww
     3 language:
     4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 
     5 */
     6 #include<bits/stdc++.h>
     7 using namespace std;
     8 const int N=100000+10;
     9 const int inf=0x3f3f3f3f;
    10 int n,a[N],f[N],h[N],t[N];//前缀&&后缀 
    11 int rd()
    12 {
    13     int x=0,w=0;char ch=0;
    14     while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    15     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    16     return w?-x:x;
    17 }
    18 
    19 int main()
    20 {
    21     n=rd();t[n+1]=h[0]=0;
    22     for(int i=1;i<=n;i++)
    23     {
    24         a[i]=rd();
    25         h[i]=h[i-1]+a[i];//前缀 
    26     }
    27     for(int i=n;i>0;i--)
    28     t[i]=t[i+1]+a[i];//后缀
    29     int mi=0;f[0]=-inf;
    30     for(int i=1;i<=n;i++)//求左区间
    31     {
    32         f[i]=h[i]-mi;
    33         f[i]=max(f[i],f[i-1]);
    34         mi=min(mi,h[i]);
    35     }
    36     int ma=-inf,ans=-inf;mi=0;
    37     for(int i=n;i>=2;i--)
    38     {
    39         ma=max(ma,t[i]-mi);
    40         ans=max(ans,ma+f[i-1]);//加答案
    41         mi=min(t[i],mi);
    42     }
    43     printf("%d",ans);
    44     return 0;
    45 }
    100昏

    T3 安装服务器

    我找到可测试原题啦 vijos1036带权中位数

    可以得两个结论

    结论1:该点一定和某个坐标点重合(我记得证的时候很玄幻 好吧是我没听
    结论2:该点一定处于左权值之和刚好大于或者等于右权值之和的那个点。(这个很好证的)
    然后就根据第一个结论就可以用枚举+递推推出来 预处理某个点到左边所有点的权值×距离差之和&这个点到右边所有点的权值×距离差之和
    有了第二个结论 就相当于是找最优的x和y
     1 /*
     2 id:gww
     3 language:
     4 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
     5 我不晓得对不对我只是有一个大胆的想法
     6 */
     7 #include<bits/stdc++.h>
     8 using namespace std;
     9 const int N=100000+5;
    10 int n,sum[N],ax,ay;
    11 int rd()
    12 {
    13     int x=0,w=0;char ch=0;
    14     while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    15     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    16     return w?-x:x;
    17 }
    18 
    19 struct lxyy
    20 {
    21     int x,y,w;//坐标 人口数*需求程度即权 
    22 }e[N];
    23 
    24 int cmp1(lxyy a,lxyy b)//排x坐标 
    25 {
    26     return a.x<b.x;
    27 }
    28 int cmp2(lxyy a,lxyy b)//排y坐标 
    29 {
    30     return a.y<b.y;
    31 }
    32 
    33 int main()
    34 {
    35     n=rd();sum[0]=0;
    36     for(int i=1;i<=n;i++)
    37     {
    38         e[i].x=rd(),e[i].y=rd();
    39         int p=rd(),k=rd();
    40         e[i].w=p*k;
    41     }
    42     sort(e+1,e+1+n,cmp1);
    43     for(int i=1;i<=n;i++)
    44     sum[i]=sum[i-1]+e[i].w;
    45     for(int i=1;i<=n;i++)
    46     if((sum[i]>=sum[n]-sum[i])&&sum[i-1]<=sum[n]-sum[i-1])
    47     {ax=e[i].x;break;}//求中位数
    48     sort(e+1,e+1+n,cmp2);
    49     for(int i=1;i<=n;i++)
    50     sum[i]=sum[i-1]+e[i].w;
    51     for(int i=1;i<=n;i++)
    52     if((sum[i]>=sum[n]-sum[i])&&sum[i-1]<=sum[n]-sum[i-1])
    53     {ay=e[i].y;break;}
    54     printf("%d %d",ax,ay);
    55     return 0;
    56 }
    100昏
  • 相关阅读:
    java初学
    数据库命名及设计规范(转)
    转-ASP.NET页面之间传递值
    程序员个人职业规划
    如何学习别人的代码(转)
    可映射的CSV读取引擎
    iTween扩展
    Unity3d中NGUI加强版血条(Healthbar)的制作
    Unity3D中寻路Navmesh的简单介绍
    多人网络(Valve开发文档翻译[起源引擎])(一)
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/10330616.html
Copyright © 2011-2022 走看看