您的位置:首页 > 其它

陕西省集训 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: