题目: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 }