N - Find a way HDU - 2612
Find a way
Pass a year learning in Hangzhou, yifenfei arrival hometown Ningbo at finally. Leave Ningbo one year, yifenfei have many people to meet. Especially a good friend Merceki.
Yifenfei’s home is at the countryside, but Merceki’s home is in the center of city. So yifenfei made arrangements with Merceki to meet at a KFC. There are many KFC in Ningbo, they want to choose one that let the total time to it be most smallest.
Now give you a Ningbo map, Both yifenfei and Merceki can move up, down ,left, right to the adjacent road by cost 11 minutes.
INPUT
- The input contains multiple test cases.
- Each test case include, first two integers n, m. (2<=n,m<=200).
- Next n lines, each line included m character.
- ‘Y’ express yifenfei initial position.
- ‘M’ express Merceki initial position.
- ‘#’ forbid road;
- ‘.’ Road.
- ‘@’ KCF
OUTPUT
- For each test case output the minimum total time that both yifenfei and Merceki to arrival one of KFC.You may sure there is always have a KFC that can let them meet.
测试样例
4 4 Y.#@ .... .#.. @..M 4 4 Y.#@ .... .#.. @#.M 5 5 Y..@. .#... .#... @..M. #...#
样例输出
66 88 66
题意理解:
- 给一个定一个矩阵是地图,‘#’是墙不可通过,‘.’是路可以通过,‘@’是目的地KFC,Y和M是两人,要去KFC见面,求二人到KFC最短距离。
- 每走一步要11分钟求最短时间。
解题思路:
这道题是迷宫的升级版,看到求最优基本排除dfs,dfs肯定会超时,选用dfs。思路没有那么高深,就是两遍dfs,分别从两给人开始dfs出两个人到KFC的距离,然后保存一下,最后选一个最短就可以了。
代码如下:
代码:
#include<iostream>
#include<queue>
#include<cstring>
#include<stdio.h>
using namespace std;
const int inf = 0x3f3f3f3f;
char mapn[1000][1000];
int visy[1000][1000];
int vism[1000][1000];
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
int vis[1000][1000];
int m,n;
struct point{
int x,y;
int countn;
};
int check(point p)
{
if(p.x>=m||p.y>=n||p.x<0||p.y<0||mapn[p.x][p.y]=='#'||vis[p.x][p.y]==1)
return 1;
return 0;
}
int bfsy(int i,int j)
{
queue<point> q;
point p;
p.x = i;
p.y = j;
p.countn = 0;
q.push(p);
vis[p.x][p.y] = 1;
while(!q.empty())
{
point p1;
p1 = q.front();
//cout<<'#'<<p1.countn<<endl;
//cout<<p1.x<<p1.y<<endl;
q.pop();
if(mapn[p1.x][p1.y] == '@')
{
visy[p1.x][p1.y] = p1.countn;
//cout<<p1.x<<','<<p1.y<<':'<<p1.countn<<endl;
}
for(int k=0;k<4;k++)
{
point p2;
p2.x = p1.x + dx[k];
p2.y = p1.y + dy[k];
p2.countn = 0;
if(p2.countn <= p1.countn + 1)
p2.countn = p1.countn + 1;
if(check(p2))
continue;
vis[p2.x][p2.y] = 1;
q.push(p2);
}
}
return 0;
}
int bfsm(int i,int j)
{
queue<point> q;
point p;
p.x = i;
p.y = j;
p.countn = 0;
q.push(p);
while(!q.empty())
{
point p1;
p1 = q.front();
q.pop();
if(mapn[p1.x][p1.y] == '@')
{
vism[p1.x][p1.y] = p1.countn;
}
for(int k=0;k<4;k++)
{
point p2;
p2.x = p1.x + dx[k];
p2.y = p1.y + dy[k];
p2.countn = 0;
if(p2.countn < p1.countn + 1)
p2.countn = p1.countn + 1;
if(check(p2))
continue;
vis[p2.x][p2.y] = 1;
q.push(p2);
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
point Y,M;
while(~scanf("%d%d",&m,&n))
{
memset(vism,-1,sizeof(vism));
memset(visy,-1,sizeof(visy));
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>mapn[i][j];
if(mapn[i][j]=='Y')
{
Y.x = i;
Y.y = j;
}
if(mapn[i][j]=='M')
{
M.x = i;
M.y = j;
}
}
}
memset(vis,0,sizeof(vis));
bfsy(Y.x,Y.y);
memset(vis,0,sizeof(vis));
bfsm(M.x,M.y);
int minn = inf;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(visy[i][j] > 0)
{
//cout<<visy[i][j]+vism[i][j]<<endl;
minn = min(minn,(visy[i][j]+vism[i][j])*11);
}
}
}
cout<<minn<<endl;
}
return 0;
}
M - 非常可乐 HDU - 1495
非常可乐
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
INPUT
- 三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
OUTPUT
- 如果能平分的话请输出最少要倒的次数,否则输出"NO"。
测试样例
7 4 3 4 1 3 0 0 0
样例输出
NO 3
题意理解:
- 有三个杯子容量为S、N、M,其中S = M + N。
- 最开始S是满的,M、N均为空。
- 输入S、M、N三个数求能不能通过来回倒可乐实现将S的可乐平分,输出最少次数或者NO。
- 每次只能将杯中的可乐全部倒入另一个杯子中,或者将另一个杯子倒满。
- 注意:这个题需要将可乐想成离散的,每次倒的都是整数毫升,或者把杯子想成只能是整数毫升。
解题思路:
这道题还是求最优解,所以还是一道bfs题,最开始的状态是S是满的N和M都是0,每次倒可乐有六种情况:
- S->N
- N->S
- S->M
- M->S
- N->M
- M->N
直到达到两杯中可乐相等一杯空就bfs结束,返回时间,如果到结束也没有这种情况就返回-1,然后就可以写bfs了,设一个三维数组去记录状态vis[s][n][m]设一个count去计数,我得做法是写一个结构体,有四个参数s、n、m和countn计数,
不会写的可以参考这篇文章:https://blog.csdn.net/qq_31267769/article/details/88782954
代码如下:
代码:
#include<iostream>
#include<stdio.h>
#include<queue>
#include<cstring>
using namespace std;
int vis[101][101][101];
struct node{
int s;
int n;
int m;
int countn;
};
int verify(int i,int j,int k,int s)
{
if((i==j&&i==s/2)||(i==k&&i==s/2)||(j==k&&j==s/2))
return 1;
return 0;
}
int bfs(int s,int n,int m)
{
if(s % 2 == 1)///奇数无法平分
return -1;
queue<node> q;
node Node;
Node.s = s;
Node.n = 0;
Node.m = 0;
Node.countn = 0;
q.push(Node);
while(!q.empty())
{
node n1 = q.front();
q.pop();
///s->n
node n2;
if(verify(n1.s,n1.n,n1.m,s))
return n1.countn;
if(n1.s>0&&n-n1.n>0)
{
int muchn = n-n1.n;
//int mushs = s-n1.s;
if(n1.s>=muchn)
{
n2.s = n1.s-muchn;
n2.n = n;
n2.m = n1.m;
}
else
{
n2.s = 0;
n2.n = n1.n+n1.s;
n2.m = n1.m;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
///n->s
if(n1.n>0&&s-n1.s>0)
{
//int muchn = n-n1.n;
int muchs = s-n1.s;
if(n1.n>=muchs)
{
n2.n = n1.n-muchs;
n2.s = s;
n2.m = n1.m;
}
else
{
n2.n = 0;
n2.s = n1.s+n1.n;
n2.m = n1.m;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
///s->m
if(n1.s>0&&m-n1.m>0)
{
int muchm = m-n1.m;
//int mushs = s-n1.s;
if(n1.s>=muchm)
{
n2.s = n1.s-muchm;
n2.m = m;
n2.n = n1.n;
}
else
{
n2.s = 0;
n2.m = n1.m+n1.s;
n2.n = n1.n;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
///m->s
if(n1.m>0&&s-n1.s>0)
{
//int muchn = n-n1.n;
int muchs = s-n1.s;
if(n1.m>=muchs)
{
n2.m = n1.m-muchs;
n2.s = s;
n2.n = n1.n;
}
else
{
n2.m = 0;
n2.s = n1.s+n1.m;
n2.n = n1.n;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
///n->m
if(n1.n>0&&m-n1.m>0)
{
int muchm = m-n1.m;
//int mushs = s-n1.s;
if(n1.n>=muchm)
{
n2.n = n1.n-muchm;
n2.m = m;
n2.s = n1.s;
}
else
{
n2.n = 0;
n2.m = n1.m+n1.n;
n2.s = n1.s;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
///m->n
if(n1.m>0&&n-n1.n>0)
{
//int muchn = n-n1.n;
int muchn = n-n1.n;
if(n1.m>=muchn)
{
n2.m = n1.m-muchn;
n2.n = n;
n2.s = n1.s;
}
else
{
n2.m = 0;
n2.n = n1.n+n1.m;
n2.s = n1.s;
}
if(vis[n2.s][n2.n][n2.m] == 0)
{
vis[n2.s][n2.n][n2.m] = 1;
n2.countn = n1.countn+1;
q.push(n2);
}
}
}
return -1;
}
int main()
{
int s,n,m;
while(scanf("%d%d%d",&s,&n,&m) != EOF)
{
memset(vis,0,sizeof(vis));
vis[s][0][0] = 1;
if(n==0&&m==0&&s==0)
break;
int ans = bfs(s,n,m);
if(ans <0)
cout<<"NO"<<endl;
else
cout<<ans<<endl;
}
return 0;
}
总结:
写bfs就是十分的长(可能我写的不是专业选手的写法)。
还有就是一定要
打标记!!!
不然内存会爆!!!
多组输入数据的时候一定要记得
清空标记!!!
不然这bug不注意能调一天
血一样的教训,这两个题都是,多组数据之间忘了清空标记了,怎么改都不对。。。断断续续改了有一整天。。