【BFS·思维】Pohlepko--7.2测试 COCI
样例
4 5
ponoc
ohoho
hlepo
mirko
4 5
bbbbb
bbbbb
bbabb
bbbbb
2 5
qwert
yuiop
分析
首先,不管怎么走,走出来的字符串是长度相等的,这个比较好理解
那么,字典序的比较就决定于比到的第一个不一样的字符
所以我们每次走的时候就比较一下右边和下边,走最小的那边
于是,第一个骗分程序:
//50%
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define LL long long
#define MAXN 2005
int n,m,cnt;
char s[MAXN][MAXN],ans[MAXN*2];
const int dx[]={0,1},dy[]={1,0};
bool check(int x,int y)
{
if(x<1||x>n||y<1||y>m)
return 0;
return 1;
}
void dfs(int r,int c)
{
//printf("%d %d\n",r,c);
if(r==n&&c==m) return ;
char tmp=123;
int nx,ny;
int x=r+dx[0],y=c+dy[0];
if(check(x,y))
tmp=s[x][y],nx=x,ny=y;
//if(r==4&&c==4) printf("%d %d\n",nx,ny);
x=r+dx[1],y=c+dy[1];
if(check(x,y))
{
if(s[x][y]<tmp)
{
ans[++cnt]=s[x][y];
dfs(x,y);
return ;
}
}
ans[++cnt]=tmp;
dfs(nx,ny);
return ;
}
int main()
{
//freopen("imena.in","r",stdin);
//freopen("imena.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
ans[++cnt]=s[1][1];
dfs(1,1);
puts(ans+1);
return 0;
}
它是不能处理相等的情况的,所以只能过
50
%
50%
50%
然后,我就开始想剩下的 50 % 50% 50%
1.
d
f
s
dfs
dfs能不能设置一个返回值,传回来一个反馈 用这个反馈来指引走哪条路
想法很美好,但是我不会写 或许周六放假会回去试一试
就是碰到了相同的就分别都搜下去
看看搜到了些什么
直到搜到了有一个节点 它的右边跟下边不同
然后传参什么的回来就是在哪里(往哪边走)找到一个最小的(这么一想 好像跟正解有点相似
2.这么一想,也就是当前我走哪条路是要取决于后面的走法的
也就是说,我选择的路,是选右边和下边的子串最小的那条
于是我就想到了dp 从左下角推倒右上角
然后就产生了第二种50分算法:
//
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
#define LL long long
#define MAXN 2005
#define INF 0x3f3f3f3f
int n,m;
char s[MAXN][MAXN];
string val[MAXN][MAXN];
int main()
{
freopen("pohlepko.in","r",stdin);
freopen("pohlepko.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
val[n][m]=s[n][m];
for(int j=m-1;j>=1;j--)
val[n][j]=s[n][j]+val[n][j+1];
for(int i=n-1;i>=1;i--)
val[i][m]=s[i][m]+val[i+1][m];
for(int i=n-1;i>=1;i--)
for(int j=m-1;j>=1;j--)
{
if(val[i+1][j]<val[i][j+1])
val[i][j]=s[i][j]+val[i+1][j];
else val[i][j]=s[i][j]+val[i][j+1];
}
cout<<val[1][1]<<endl;
return 0;
}
我当时觉得这个简直就是
p
e
r
f
e
c
t
perfect
perfect
结果
M
L
E
MLE
MLE了
对 我相当于存了所有的情况 字符串太长了然后就爆栈了
q
w
q
qwq
qwq
然后,就是正解:
类似于广搜
遇到相等的情况 就继续搜下去
搜索树中的同一层 找到最小的那个 我们就走最小的那个
其它的可以丢了
如果最小的有多个 就继续搜索每一个最小的
//
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
#include<queue>
using namespace std;
#define LL long long
#define MAXN 2005
#define INF 0x3f
int n,m;
char s[MAXN][MAXN];
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int d[MAXN][MAXN],cnt[MAXN*2];
int w[MAXN][MAXN];//路径
bool vis[MAXN][MAXN];
queue<int>Q1,Q2;
void bfs()
{//d是搜索树里的层数 cnt是这一层里最小的字母-'a'
memset(cnt,0x3f,sizeof(cnt));
vis[1][1]=1;
d[1][1]=1;
cnt[1]=s[1][1]-'a';
while(!Q1.empty()) Q1.pop();
while(!Q2.empty()) Q2.pop();
Q1.push(1);
Q2.push(1);
while(!Q1.empty())
{
int x=Q1.front(),y=Q2.front();
Q1.pop();Q2.pop();
if(s[x][y]-'a'!=cnt[d[x][y]])
continue;
//不等的话 就是之前比较的时候还没有比到最小值 它是之前的当前最小值 而我们只继续搜字典序最小的那一个或那几个
for(int i=0;i<=1;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!vis[nx][ny])
{
d[nx][ny]=d[x][y]+1;
vis[nx][ny]=1;
if(cnt[d[nx][ny]]>=s[nx][ny]-'a')
{
cnt[d[nx][ny]]=s[nx][ny]-'a';
Q1.push(nx); Q2.push(ny);
//拓展下一层节点的话 就只push字典序最小的那一个或那几个
w[nx][ny]=i+2;//到(w1,w2)这个节点来 是上一个位置通过d[]数组i+2到的
//实际上的路径只需要记录最小的那一条
//记录下来所有可能的路径(有的是当前最小 会被淘汰 整个节点都是无效的
}
}
}
}
}
void print(int x,int y)
{
//printf("%d %d\n",x,y);
if(x==1&&y==1)
{
printf("%c",s[x][y]);
return ;
}
print(x+dx[w[x][y]],y+dy[w[x][y]]);
printf("%c",s[x][y]);
}
int main()
{
freopen("pohlepko.in","r",stdin);
freopen("pohlepko.out","w",stdout);
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
bfs();
print(n,m);
return 0;
}