• NOIP 2013 提高组 Day2


    题目:http://wenku.baidu.com/link?url=1F3SWpM03sBYFuLG_We0yHupksYPOn2Y3Ly7rhaurzlvDMCxgStK79GnsAxSA5lzXm0083FBrziHOSNCBm4oyniA0FGnSnlgsHeK-p9gq3

    1.积木大赛

    [分治]

      提示:不会重复运算,O(n);以0为界;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #include<algorithm>
     5 #include<cstring>
     6 using namespace std;
     7 int h[100005],n;
     8 int ans;
     9 void find(int l,int r)
    10 {
    11     if(l>r)return ;
    12     if(l==r)
    13     {
    14         ans+=h[l];
    15         return ;
    16     }
    17     int min=h[l],k=l;
    18     for(int i=l+1;i<=r;i++)
    19     {
    20         if(h[i]<min)min=h[i];
    21         k=i;
    22     }
    23     ans+=min;
    24     for(int i=l;i<=r;i++)
    25     {
    26         h[i]-=min;
    27         if(h[i]==0)
    28         {
    29             find(l,i-1);
    30             l=i+1;
    31         }
    32     }
    33     find(l,r);
    34     return ;
    35     
    36 }
    37 int main()
    38 {
    39     freopen("block.in","r",stdin);
    40     freopen("block.out","w",stdout);
    41     scanf("%d",&n);
    42     for(int i=1;i<=n;i++)
    43     scanf("%d",&h[i]);
    44     find(1,n);
    45     cout<<ans;
    46     return 0;
    47 }

    [线性算法]

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #include<algorithm>
     5 #include<cstring>
     6 using namespace std;
     7 int h[100005],n;
     8 int ans;
     9 int main()
    10 {
    11     freopen("block.in","r",stdin);
    12     freopen("block.out","w",stdout);
    13     scanf("%d",&n);
    14     for(int i=1;i<=n;i++)
    15     {
    16         scanf("%d",&h[i]);
    17         if(h[i]>h[i-1])ans+=h[i]-h[i-1];
    18     }
    19     cout<<ans;
    20     return 0;
    21 }

    2.花匠

    [找拐点]

      注意:ans=边数;即答案为ans+1;把ans初始值为1就可以了;

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 #include<algorithm>
     5 #include<cstring>
     6 using namespace std;
     7 int  n,m,q;
     8 const int zl[2][4]={{1,-1,0,0},{0,0,1,-1}};
     9 bool map[35][35];
    10 bool b[35][35][35][35];
    11 struct M{
    12     int bx,by,lx,ly,step;
    13 };
    14 
    15 bool can(M s)
    16 {
    17     if(b[s.bx][s.by][s.lx][s.ly])return false;
    18     if(!map[s.bx][s.by]||s.bx<1||s.by<1||s.bx>n||s.by>m)
    19         return false;
    20     return true;
    21 }
    22 void bfs()
    23 {
    24     memset(b,false,sizeof(b));
    25     queue<M>q;
    26     M u;
    27     int endx,endy;
    28     scanf("%d%d%d%d%d%d",&u.bx,&u.by,&u.lx,&u.ly,&endx,&endy);
    29     u.step=0;
    30     if(u.lx==endx&&u.ly==endy){
    31         printf("0
    ");
    32         return ;
    33     }
    34     q.push(u);
    35     b[u.bx][u.by][u.lx][u.ly]=true;
    36     while(!q.empty())
    37     {
    38         M k=q.front();
    39         q.pop();
    40         for(int i=0;i<=3;i++)
    41         {
    42             M s=k;
    43             s.bx+=zl[0][i];
    44             s.by+=zl[1][i];
    45             if(s.bx==s.lx&&s.by==s.ly)
    46             {    
    47                 s.lx=k.bx;
    48                 s.ly=k.by;
    49             }
    50             if(can(s))
    51             {
    52                 s.step=k.step+1;
    53                 b[s.bx][s.by][s.lx][s.ly]=true;
    54                 if(s.lx==endx&&s.ly==endy)
    55                 {
    56                     printf("%d
    ",s.step);
    57                     return;
    58                 }
    59                 q.push(s);
    60             }
    61         }
    62     }
    63     printf("-1
    ");
    64     return ;
    65 }
    66 int main()
    67 {
    68     freopen("puzzle.in","r",stdin);
    69     freopen("puzzle.out","w",stdout);
    70     cin>>n>>m>>q;
    71     for(int i=1;i<=n;i++)
    72     for(int j=1;j<=m;j++)
    73     {
    74         int x;
    75         scanf("%d",&x);
    76         map[i][j]=x;
    77     }
    78     for(int i=1;i<=q;i++)
    79     bfs();
    80     return 0;
    81 }

    [正解]

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <queue>
      6 #define MaxN 35
      7 using namespace std;
      8 const int 
      9     INF=~0U>>2,
     10     dx[]={0,0,-1,1},
     11     dy[]={-1,1,0,0};//注意顺序,才易实现0变1,1变0;2变3,3变2 
     12 int mat[MaxN][MaxN],dis[MaxN][MaxN][4];
     13 bool vis[MaxN][MaxN][4];
     14 int step[MaxN][MaxN][4][4];
     15 int d[MaxN][MaxN];
     16 int n,m,q,test,ex,ey,sx,sy,tx,ty;
     17 struct node
     18 {
     19        int x,y;
     20 };
     21 struct node2
     22 {
     23        int x,y,k;
     24 };
     25 bool inside(int x, int y)
     26 {
     27     return (x>=1&&x<=n&&y>=1&&y<=m);
     28 }
     29 int spfa()
     30 {
     31     queue<node2> q;
     32     memset(vis,false,sizeof(vis));
     33     while(!q.empty()) q.pop();//局部队列,可能非空,所以清空 
     34     for(int k=0;k<4;k++)//把初始位置棋子与空格相邻,四个方向组成的四种可能的步数入队,当成四个源点。 
     35         if(dis[sx][sy][k]!=INF)
     36         {    
     37             q.push((node2){sx,sy,k});
     38             vis[sx][sy][k]=true;
     39         }
     40     while(!q.empty())
     41     {    
     42         int x=q.front().x;
     43         int y=q.front().y;
     44         int k=q.front().k;
     45         q.pop();
     46         vis[x][y][k]=false;
     47         for(int i=0;i<4;i++)
     48         {
     49             int _x=x+dx[i];//棋子(x,y)扩展的点(_x,_y)
     50             int _y=y+dy[i];
     51             if(inside(_x,_y))
     52             if(mat[_x][_y])
     53             if(step[x][y][k][i]!=INF)//棋子(x,y)k方向空格可以移到棋子(x,y)i方向。 
     54             if(dis[_x][_y][i^1]>dis[x][y][k]+step[x][y][k][i]+1) 
     55             {//棋子(x,y)k方向空格移到棋子(x,y)i方向,再把棋子移到空格上,所以+1,空格变成i^1方向。
     56                 dis[_x][_y][i^1]=dis[x][y][k]+step[x][y][k][i]+1;
     57                 if (not vis[_x][_y][i^1])
     58                  { 
     59                    q.push((node2){_x,_y,i ^ 1 });
     60                    vis[_x][_y][i^1]=true;
     61                  }
     62             }
     63         }
     64     }
     65     int ans=INF;
     66     for(int i=0;i<4;i++)
     67         if(dis[tx][ty][i]<ans)
     68             ans=dis[tx][ty][i];//找出目标位置与空格相邻四种情况最少步数 
     69     return (ans==INF)? -1:ans;
     70 }
     71 int bfs(int sx,int sy,int tx,int ty)//将空格从(sx,sy)移到(tx,ty)的步数 
     72 {
     73     if(!mat[sx][sy])
     74         return INF;
     75     if(!mat[tx][ty])
     76         return INF;
     77     for(int i=1;i<=n;i++)
     78         for(int j=1;j<=m;j++) 
     79             d[i][j]=INF;//INF可以做为没有到过的标志 
     80     d[sx][sy]=0;
     81     queue<node> q;//局部队列,可能非空,所以清空 
     82     while(!q.empty()) q.pop();
     83     q.push((node){sx,sy});
     84     while(!q.empty())
     85     {
     86         if(d[tx][ty]!=INF)
     87           return d[tx][ty];
     88         int x=q.front().x;
     89         int y=q.front().y;
     90         q.pop();
     91         for(int i=0;i<4;i++)
     92         {
     93             int _x=x+dx[i];
     94             int _y=y+dy[i];
     95             if(inside(_x,_y))
     96                 if(mat[_x][_y]&&d[_x][_y]==INF)
     97                 {
     98                     d[_x][_y]=d[x][y]+1;
     99                     //if(d[tx][ty]!=INF)
    100                     //   return d[tx][ty];
    101                     //与下面不等价,有可能(sx,sy)与(tx,ty)一样,所以最好放在出队前判断 
    102                     //if (_x==tx&&_y==ty) return d[tx][ty];????
    103                     q.push((node){_x,_y});
    104                 }
    105         }
    106     }
    107     return INF;
    108 }
    109 void init()
    110 {
    111     for(int i=1;i<=n;i++)
    112         for(int j=1;j<=m;j++)
    113         {
    114              int v=mat[i][j];
    115             mat[i][j]=0;//此位置可能是0或1,均改成0,因为移动空格不能移动棋子(i,j) 
    116             for (int k=0;k<4;k++)
    117                 for (int l=0;l<4;l++) 
    118                      step[i][j][k][l]=bfs(i+dx[k],j+dy[k],i+dx[l],j+dy[l]);
    119                 //step[i][j][k][l] 棋子(i,j)k方向相邻的空格移动到相邻的l方向的步数,
    120              mat[i][j]=v;//还原
    121         }
    122 }    
    123 int getAns()
    124 {
    125     scanf("%d%d%d%d%d%d",&ex,&ey,&sx,&sy,&tx,&ty);
    126     if(sx==tx&&sy==ty)//初始位置与目标位置同,0步
    127         return 0;
    128     if(sx==ex&&sy==ey)//初始位置与空格位置同,无解
    129         return -1;
    130     if(!inside(ex,ey)||!inside(sx,sy)||!inside(tx,ty))//三个位置至少有一个在棋盘外
    131         return -1;
    132     if(!mat[ex][ey]||!mat[sx][sy]||!mat[tx][ty])////三个位置至少有一个是固定的
    133         return -1;
    134     for(int i=1;i<=n;i++)
    135         for (int j=1;j<=m;j++)
    136             for (int k=0;k<4;k++)
    137                 dis[i][j][k]=INF;
    138     mat[sx][sy]=0;//此时一定是1,改成0,因为前面已经判断过 
    139     for(int k=0;k<4;k++)
    140          dis[sx][sy][k]=bfs(ex,ey,sx+dx[k],sy+dy[k]);
    141     //dis[sx][sy][k]表示将空格移到(sx,sy)相邻并在k方向上的步骤 
    142     mat[sx][sy]=1; //还原 
    143     return spfa();
    144 }
    145 int main()
    146 {
    147     freopen("puzzle.in","r",stdin);
    148     freopen("puzzle.out","w",stdout);
    149     scanf("%d%d%d",&n,&m,&test);
    150     for(int i=1;i<=n;i++)
    151         for(int j=1;j<=m;j++)
    152             scanf("%d",&mat[i][j]);
    153     init();
    154     while(test--)
    155         printf("%d
    ",getAns());
    156     return 0;
    157 }
  • 相关阅读:
    设计模式七大原则之单一职责原则
    机器学习入门与进阶
    Django之路
    Python编程之路
    Python练习1
    Docker入门与进阶
    运维相关
    Node.js(一)
    位运算
    双指针算法
  • 原文地址:https://www.cnblogs.com/nigulasi/p/5664868.html
Copyright © 2020-2023  润新知