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 }
原文地址:https://www.cnblogs.com/nigulasi/p/5664868.html