陕西省集训 day4(搜索下)
2016-08-24 01:51
274 查看
A题:
http://codeforces.com/problemset/problem/540/C题意:
从起始点到终止点走,’ . ‘表示裂的冰,‘X’表示已经碎了不能走了(起点可以),’ . ‘走过变成’ X ‘,最后要求这个人的末位置冰碎掉。思路:
就是说最后末尾位置如果是’。’,要绕出去再回来踩碎它。。。当时读题半个小时QAQ#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; typedef pair<int,int> pii; queue<pii>q; char s[510][510]; int stx,sty,enx,eny; int n,m; int vis[510][510]; int dir[4][2] = { {0,1},{-1,0},{1,0},{0,-1} }; int mp[4] = {1,2,3,4}; int bfs() { pii ps = make_pair(stx-1,sty-1); q.push(ps); while(!q.empty()) { pii tmp = q.front(); q.pop(); int tmx = tmp.first,tmy = tmp.second; if(vis[enx-1][eny-1] == 2) return 1; for(int i = 0 ; i < 4 ;i++) { int nox = tmx+dir[i][0]; int noy = tmy+dir[i][1]; if(nox >=0&&nox<n&&noy >=0&&noy <m &&s[nox][noy] =='.' &&!vis[nox][noy] || nox == enx-1&&noy == eny-1) { vis[nox][noy] ++; // cout << nox <<" "<<noy <<endl; q.push(make_pair(nox,noy)); } } } return 0; } int main() { cin>> n >>m; for(int i = 0 ; i < n ;i++) { scanf("%s",s[i]); for(int j = 0 ; j < m;j++) if(s[i][j] == 'X') vis[i][j]++; } cin >> stx>>sty>>enx>>eny; if(bfs()) cout << "YES"<<endl; else cout <<"NO"<<endl; return 0; }
B题:
题意:
两个人,一个从左上角到右下角,每次只能向下走或者向右走,另外一个人从右上角到左下角,只能向下或者向左,使得两条线路做经过的数字的和最大(交叉点的数字两条路线都不算进去)思路:
从4个角分别向对角做dp,然后这样的话就可以得到每个点到4个角的最大值,接下来循环扫描每一个点作为交叉点,找出和最大的路径,但是到这里如果不加思考直接做的话就会出问题,因为对于不在边界上的任何一个点,从左上方来的话只能是从上方或者左方来,而从右上方来的话就会从这个点的上方和右方来,另外两个点也是如此,先分析这两个方向,他们有一个共同的来向,如果直接用当前点到4个角的最大值的和减去4倍的这个点的值,就有可能发生重叠,导致在这点之前路线就交叉了,显然不合题意,分析下来,交叉处只有两个选项,左上角的顶点从左方来,右下角的定点从右边来,或者是左上角的顶点从上方来,右下角的顶点从下方来,这是要注意的一个点,如果你分析了这一点的话,很容易知道边界点不可能是交叉点。#include <iostream> #include <cstdio> #include <cstring> #define maxn 1005 using namespace std; int dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn]; int a[maxn][maxn]; int main() { int n,m; cin >> n >>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&a[i][j]); } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { dp1[i][j] = max(dp1[i-1][j],dp1[i][j-1]) + a[i][j]; } } for(int i=n;i>=1;i--) { for(int j=m;j>=1;j--) { dp2[i][j] = max(dp2[i+1][j],dp2[i][j+1]) + a[i][j]; } } for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { dp3[i][j] = a[i][j] + max(dp3[i-1][j], dp3[i][j+1]); } } for(int i=n;i>=1;i--) { for(int j=1;j<=m;j++) { dp4[i][j] = a[i][j] + max(dp4[i][j-1], dp4[i+1][j]); // cout << dp4[i][j] <<endl; } } int ans = 0; for(int i=2;i<n;i++) { for(int j=2;j<m;j++) { ans = max(ans,dp1[i-1][j]+dp2[i+1][j]+dp3[i][j+1]+dp4[i][j-1]); ans = max(ans,dp1[i][j-1]+dp2[i][j+1]+dp3[i-1][j]+dp4[i+1][j]); } } cout << ans <<endl; return 0; }
C题:
题意:
从(1,1)走到(n,m),输入表示从(x1,y1)到 (x2,y2)需要第一把钥匙,0表示不需要,然后告诉你走到(x1,y1)处,你将得到哪个钥匙,可以多次使用,问最快什么时候走出去,不能走出去输出-1思路:
钥匙怎么表示?一共最多9把,那么就可以用2进制表示这9把钥匙,0表示该位置上对应的第一把钥匙是没有的,1表示有,每次到了一个点(可能一个点有多把),把获得的钥匙相应位置标1,如果没有就接着搜索#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define maxn 55 using namespace std; int dir[4][2] = { {0,1},{0,-1},{-1,0},{1,0} }; int r,c,k,n; int path[maxn][maxn]; int door[maxn][maxn][maxn][maxn]; int key[maxn][maxn]; bool vis[maxn][maxn][1025]; typedef pair < pair<int,int>,int> pi3; #define mp3(a,b,c) make_pair(make_pair(a,b),c) int bfs() { queue<pi3> q; q.push(mp3(1,1,key[1][1])); path[1][1] = 0; memset(vis,0,sizeof(vis)); while(!q.empty()) { pi3 tmp = q.front(); q.pop(); int s1 = tmp.first.first; int s2 = tmp.first.second; int s3= tmp.second; if(s1 == r && s2 == c) return 1; for(int i = 0 ; i <4 ;i++) { //cout <<"asd" <<endl; int x = tmp.first.first+dir[i][0]; int y = tmp.first.second+dir[i][1]; // cout <<"aa"<<r<<" "<<c <<" "<<x<<" " <<y <<" "<<vis[x][y][s3|key[x][y]]<<endl; if(x > 0 && x<=r && y >0 && y <= c && !vis[x][y][s3|key[x][y]]){ // cout <<"YES"<<endl; int z = s3|(key[x][y]); // cout <<"z = "<<z<<" dor "<<s1<<" "<<s2<<" "<<x<< " " <<y <<" "<<door[s1][s2][x][y]<<endl; // cout <<"sdf "<<(z >>(door[s1][s2][x][y]-1)&1)<<endl; if(door[s1][s2][x][y] == -1 || (door[s1][s2][x][y]&&(z >>(door[s1][s2][x][y]-1)&1) )){ // cout <<" YES"<<endl; vis[x][y][z] = 1 ; q.push(mp3(x,y,z)); path[x][y] = path[s1][s2]+1; // cout << " aaaa" <<x << " "<<y<<" " <<path[x][y]<<endl; } } } } return 0; } int main() { int a,b,cc,d,dr,ky; while(cin >> r >>c >> k>>n) { memset(door,-1,sizeof(door)); memset(key,0,sizeof(key)); for(int i = 0 ; i < n ;i++){ scanf("%d%d%d%d%d",&a,&b,&cc,&d,&dr); door[a][b][cc][d] = dr; door[cc][d][a][b] = dr; } int s; cin >> s; for(int i = 0 ; i < s ;i++){ scanf("%d%d%d",&a,&b,&ky); key[a][b] |= 0|(1<<(ky-1)); } if(bfs()) cout << path[r][c]<<endl; else cout <<-1<<endl; //cout <<(0|(1<<(4-1)))<<endl; } return 0; }
D题:
题意:
简单版推箱子、先保证推箱子走的距离最少,在保证人自己走的最少思路:
搜索肯定是要搜了,这里注意,这个注意要bfs套bfs,就是说大方向是箱子决定方向,人呢,根据箱子要走的方向走到相应位置,比如箱子要往上走,那人就要走到他下面,左走在右等等,就可以保证了题意要求的#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0} }; int vb[25][25],vp[25][25]; char s[25][25]; char pathb[5] = {'E','W','S','N'}; char pathp[5] = {'e','w','s','n'}; string tmp_ans= ""; int n,m,spx,spy,sbx,sby,enx,eny; struct person { int x, y; string path; }; struct box { int x,y; int px,py; string path; }; int yy = 0; int bfsp(int npx,int npy,int tox,int toy,int nbx,int nby) { queue<person>qp; yy++; if(tox <0||tox>=n||toy <0 ||toy>=m) return 0; memset(vp,0,sizeof(vp)); person tmp; tmp.x = npx,tmp.y = npy,tmp.path = ""; qp.push(tmp); vp[tmp.x][tmp.y] = 1; while(!qp.empty()) { person tmp = qp.front(); qp.pop(); if(tmp.x == tox && tmp.y == toy) { // if(yy == 2) // cout <<" " <<tmp.x <<" " <<tmp.y<<endl; tmp_ans = tmp.path; return 1; } for(int i = 0 ; i < 4; i++) { int nowx = tmp.x+dir[i][0]; int nowy = tmp.y+dir[i][1]; if(nowx >=0 &&nowx < n && nowy >=0 &&nowy < m && !vp[nowx][nowy] &&!(nowx == nbx&&nowy == nby) ) { if(s[nowx][nowy] != '#') { vp[nowx][nowy] = 1; person tl; tl.x = nowx,tl.y = nowy,tl.path = tmp.path+pathp[i]; qp.push(tl); } } } } return 0; } void bfsb() { queue<box>qb; box sta; sta.x = sbx,sta.y = sby,sta.px = spx,sta.py = spy,sta.path = ""; qb.push(sta); vb[sta.x][sta.y] = 1; while(!qb.empty()) { box tmp = qb.front(); qb.pop(); if(tmp.x == enx && tmp.y == eny) cout <<tmp.path; for(int i = 0 ; i < 4 ;i++) { int nowx = tmp.x+dir[i][0]; int nowy = tmp.y+dir[i][1]; if(nowx >=0 &&nowx < n && nowy >=0 &&nowy < m && !vb[nowx][nowy]) { if(s[nowx][nowy] !='#' && bfsp(tmp.px,tmp.py,tmp.x-dir[i][0],tmp.y-dir[i][1],tmp.x,tmp.y)) { vb[nowx][nowy] = 1; box t; t.x = nowx,t.y = nowy,t.px = tmp.x,t.py = tmp.y,t.path = tmp.path+tmp_ans+pathb[i]; if(s[nowx][nowy] == 'T') { cout <<t.path<<endl; return ; } else qb.push(t); } } } } printf("Impossible.\n"); } int main() { int Case = 0; while(~scanf("%d%d",&n,&m)) { if(n == 0 && m ==0) break; // if(!qb.empty()) // qb.pop(); // if(!qp.empty()) // qp.pop(); printf("Maze #%d\n",++Case); for(int i = 0 ; i < n ;i++) { scanf("%s",s[i]); for(int j = 0 ; j < m ;j++) if(s[i][j] == 'S') spx = i,spy = j; else if(s[i][j] == 'B') sbx = i,sby = j; else if(s[i][j] == 'T') enx = i,eny = j; } memset(vb,0,sizeof(vb)); bfsb(); cout << endl; } return 0; }
E题:
这题好难题意:
两个小孩互相看不顺眼,要远离对方走,一个人不能经过另一个人的家或者学校,到了自己家或者学校之后不能在动了,两个人为了离对方最远可以循环走,不停地前后前后思路:
普通的bfs上去掉vis数组,反正可以不断的重复走,队列维护这条路上两个人最近的那点的距离#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <cmath> using namespace std; typedef pair< pair<int,int> , pair<int,int> > p4; typedef pair< int , p4 > p5; #define item1 first #define item2 second.first.first #define item3 second.first.second #define item4 second.second.first #define item5 second.second.second #define mp2(a,b) make_pair(a,b) #define mp4(a,b,c,d) make_pair(mp2(a,b),mp2(c,d)) #define mp5(a,b,c,d,e) make_pair(a,mp4(b,c,d,e)) const int MAXN = 33; const int dir[4][2] = { {0,1},{-1,0},{0,-1},{1,0} }; const char sign[4] = {'E','N','W','S'}; char s[MAXN][MAXN]; int F[MAXN][MAXN][MAXN][MAXN]; p4 Last[MAXN][MAXN][MAXN][MAXN]; int n,m; int hx,hy,Hx,Hy,sx,sy,Sx,Sy; int dist(int x1,int y1,int x2,int y2){ return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); } void Out1( int x1 , int y1 , int x2 , int y2 ) { if (x1 == Hx && y1 == Hy && x2 == hx && y2 == hy) return; p4 tmp = Last[x1][y1][x2][y2]; int x3 = tmp.first.first; int y3 = tmp.first.second; int x4 = tmp.second.first; int y4 = tmp.second.second; if ( x3 == x1 && y3 == y1 ) Out1(x3,y3,x4,y4); else { for ( int i = 0 ; i < 4 ; i ++ ) { if (x3 + dir[i][0] == x1 && y3 + dir[i][1] == y1) { Out1(x3,y3,x4,y4); printf("%c",sign[i]); break; } } } } void Out2( int x1 , int y1 , int x2 , int y2 ) { if (x1 == Hx && y1 == Hy && x2 == hx && y2 == hy) return; p4 tmp = Last[x1][y1][x2][y2]; int x3 = tmp.first.first; int y3 = tmp.first.second; int x4 = tmp.second.first; int y4 = tmp.second.second; if ( x4 == x2 && y4 == y2 ) Out2(x3,y3,x4,y4); else { for ( int i = 0 ; i < 4 ; i ++ ) { if (x4 + dir[i][0] == x2 && y4 + dir[i][1] == y2) { Out2(x3,y3,x4,y4); printf("%c",sign[i]); break; } } } } void bfs() { p5 x,y; int dis = dist(Hx,Hy,hx,hy); for ( int i = 0 ; i < n ; i ++ ) for ( int j = 0 ; j < m ; j ++ ) for ( int u = 0 ; u < n ; u ++ ) for ( int v = 0 ; v < m ; v ++ ) F[i][j][u][v] = -1; F[Hx][Hy][hx][hy] = dis ; x = mp5(dis,Hx,Hy,hx,hy); priority_queue<p5> pq; pq.push(x); while(!pq.empty()) { y = pq.top(); pq.pop(); if ( y.item2 == Sx && y.item3 == Sy && y.item4 == sx && y.item5 == sy ) break; for(int i = 0 ; i < 4; i++) for( int j = 0 ; j < 4 ; j ++) { int a = y.item2+dir[i][0]; int b = y.item3+dir[i][1]; int c = y.item4+dir[j][0]; int d = y.item5+dir[j][1]; if (y.item2 == Sx && y.item3 == Sy && y.item4 == sx && y.item5 == sy) continue; else if (y.item2 == Sx && y.item3 == Sy && (y.item4 != sx || y.item5 != sy)) { a = y.item2; b = y.item3; } else if ((y.item2 != Sx || y.item3 != Sy) && y.item4 == sx && y.item5 == sy) { c = y.item4; d = y.item5; } if(a >=0 && a<n && b >=0&&b<m &&c >=0&&c<n&&d>=0&&d<m && s[a][b] != '*'&&s[c][d] != '*' && s[a][b] != 'h' && s[a][b] != 's' && s[c][d] != 'H' && s[c][d] != 'S') { int dis = min(dist(a,b,c,d),y.item1); if ( dis > F[a][b][c][d] ) { F[a][b][c][d] = dis; Last[a][b][c][d] = mp4(y.item2,y.item3,y.item4,y.item5); pq.push(mp5(F[a][b][c][d],a,b,c,d)); } } } } printf("%.2f\n",sqrt((double)F[Sx][Sy][sx][sy])); Out1( Sx , Sy , sx , sy ) ; printf( "\n" ) ; Out2( Sx , Sy , sx , sy ) ; printf( "\n" ) ; } int main(){ while(~scanf("%d",&n) && n){ m = n; for(int i = 0 ; i < n ;i++){ scanf("%s",s[i]); for(int j = 0 ; j < n ;j++) if(s[i][j] == 'h') hx = i,hy = j; else if(s[i][j] == 'H') Hx = i ,Hy = j; else if(s[i][j] == 's') sx = i,sy = j; else if(s[i][j] == 'S') Sx = i,Sy = j; } bfs(); } return 0; }
F题:
题意:
从指定点走到指定点其中一写障碍,当走到那个点是k的倍数的时候就可以让那个障碍消失,其他时候就走不过思路:
只有vis数组需要变一下,其他仍然是bfs最基础的思路,同一个点虽然可以走很多次,但是每次%k的值肯定是不同的,不然就是走了回头路也可以把图形拓展为三维,每个点可以走到上一层或者下一层的左右前后,一个拓展k层,每一层上的每个点可以都是vis一次的=。=
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; typedef pair <pair<int,int> ,int> pii; #define mp3(a,b,c) make_pair( make_pair(a,b) ,c) char s[110][110]; int path[110][110][10]; int vis[110][110][10]; int dir[4][2] = { {0,1},{0,-1},{1,0},{-1,0}}; int r,c,k; int sx,sy,ex,ey; void bfs() { queue<pii> q; q.push(mp3(sx,sy,0)); memset(path,0,sizeof(path)); vis[sx][sy][0] = 1; while(!q.empty()){ pii tmp = q.front(); q.pop(); if(tmp.first.first == ex && tmp.first.second == ey){ cout << path[ex][ey][tmp.second] <<endl; return; } for(int i = 0 ; i < 4 ;i++){ int x = tmp.first.first + dir[i][0]; int y = tmp.first.second + dir[i][1]; int z = (tmp.second +1)%k; if(x >= 0 && x < r && y >= 0 && y < c){ if((s[x][y]=='.' || z == 0)&& !vis[x][y][z]){ vis[x][y][z] = 1; path[x][y][z] = path[tmp.first.first][tmp.first.second][tmp.second]+1; q.push(mp3(x,y,z)); } } } } cout << "Please give me another chance!"<<endl; } int main() { int T; cin >>T; while(T--){ scanf("%d%d%d",&r,&c,&k) ; memset(vis,0,sizeof(vis)); for(int i = 0 ; i < r ;i++){ scanf("%s",s[i]); for(int j = 0 ; j < c ;j++) if(s[i][j] == 'Y'){ sx = i,sy = j; s[i][j] = '.'; } else if(s[i][j] == 'G'){ ex = i,ey = j; s[i][j] = '.'; } } bfs(); } return 0; }
G题:
作为一个搜索的题,可以用到小学数学公式开心么?#include <iostream> #include <cstdio> using namespace std; int gcd(int a,int b) { return (b == 0)?a:gcd(b,a%b); } int main() { int c,a,b; while(~scanf("%d%d%d",&c,&a,&b) ) { if(a == 0 && b == 0 &&c == 0) break; int g = gcd(b,c); int c= a/g; int d = b/g; if((a+b)/g%2) cout << "NO\n"; else cout << (c+d-1)<<endl; } return 0; }
相关文章推荐
- 陕西省集训day3(搜索上)
- CSU-ACM2017暑假集训2-二分搜索 C - 4 Values whose Sum is 0
- 暑假集训第三周第二阶段 搜索 F - 棋盘问题
- 集训第八天(2017/8/7):白天刷搜索题+晚上看dijkstra算法
- 暑假集训日记--8.8--搜索+练习赛
- ACM集训day4
- 2014暑假集训搜索专题
- 【暑假集训专题#搜索】
- 2018年福州寒假集训Day4
- 2013-3-17 集训 Problem H: 跳格子 搜索
- 【暑假集训专题#搜索】
- loj #6136. 「2017 山东三轮集训 Day4」Left
- 省队集训 Day4 a
- 暑假集训日记--8.7--搜索+图论
- 暑假集训第三周第二阶段搜索 H - Zipper
- 暑假集训--训练1 二分搜索
- 【集训】DP & 搜索 & 线段树
- 暑假集训-搜索
- loj #6138. 「2017 山东三轮集训 Day4」Right
- [(可持久化)字典树 优化建图][2-SAT] LOJ#6036. && 雅礼集训 2017 Day4. 编码