最近在做广搜的题,一场六六欢乐赛彻底让我意识到了暴搜的重要性 所以我为什么要去做广搜。想着先把广搜的黄题刷完(听同学说广搜的橙题更难),结果这一道题我就调了大概4个小时,还是写一篇博客吧
拿到这道题,最开始是没啥思路的,因为这种题型其实是没怎么遇见过的,之前做过的大多广搜题都是基本上直接套模板,多做这种题加深理解和锻炼思维吧
最开始的思路还是先用DFS暴搜一下。函数中放四个参数,前两个参数为最基础的坐标,第三个为目前的花费,第四个记录当前是否使用魔法:对于相同颜色的情况,花费不变;对于颜色不同的情况(有颜色),花费+1;对于空白情况,花费+2,并把下一个位置涂上色(最开始没加这个调了很久)。这样的话就得到了第一个程序(60分)
#include
using namespace std;
int m,n;
int a[105][105];
bool b[105][105];
int ans=20040915; //初始化为妹子的生日(玄学优化)
int mx[4]={1,0,0,-1};
int my[4]={0,-1,1,0};
void dfs(int x,int y,int sum,bool op){
if(sum>ans) return;
if(x==m&&y==m){
ans=min(ans,sum);
return;
}
for(register int i=0;i<4;i++){
int nx=x+mx[i];
int ny=y+my[i];
if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
if(a[nx][ny]==a[x][y]){
b[nx][ny]=true;
dfs(nx,ny,sum,false);
b[nx][ny]=false;
}else if(a[nx][ny]==0&&op==false){
b[nx][ny]=true;
a[nx][ny]=a[x][y];
dfs(nx,ny,sum+2,true);
a[nx][ny]=0;
b[nx][ny]=false;
}else if(a[nx][ny]!=a[x][y]&&a[nx][ny]){
b[nx][ny]=true;
dfs(nx,ny,sum+1,false);
b[nx][ny]=false;
}
}
}
}
int main(){
scanf("%d%d",&m,&n);
for(register int i=1;i<=n;i++){
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
a[x][y]=c+1;
}
b[1][1]=true;
dfs(1,1,0,false);
if(ans==20040915){
cout<<-1;
}else{
cout<
然后继续想,发现有个记忆化搜索这种东西,开一个f数组,对于搜索的当前坐标,记录到此坐标的最小化费,对于之后大于它的花费,直接return,最后的答案就是 f [ m ][ m ](70分)
#include
using namespace std;
int m,n;
int a[105][105];
bool b[105][105];
int mx[4]={1,0,0,-1};
int my[4]={0,-1,1,0};
int f[105][105];
inline void dfs(int x,int y,int sum,bool op){
if(sum>f[x][y]) return;
f[x][y]=sum;
for(register int i=0;i<4;i++){
int nx=x+mx[i];
int ny=y+my[i];
if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
if(a[nx][ny]==a[x][y]){
b[nx][ny]=true;
dfs(nx,ny,sum,false);
b[nx][ny]=false;
}else if(a[nx][ny]==0&&op==false){
b[nx][ny]=true;
a[nx][ny]=a[x][y];
dfs(nx,ny,sum+2,true);
a[nx][ny]=0;
b[nx][ny]=false;
}else if(a[nx][ny]!=a[x][y]&&a[nx][ny]){
b[nx][ny]=true;
dfs(nx,ny,sum+1,false);
b[nx][ny]=false;
}
}
}
return ;
}
int main(){
scanf("%d%d",&m,&n);
for(register int i=1;i<=m;i++) fill(f[i]+1,f[i]+1+m,20040915);
for(register int i=1;i<=n;i++){
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
a[x][y]=c+1;
}
b[1][1]=true;
dfs(1,1,0,false);
if(f[m][m]==20040915){
puts("-1");
}else{
printf("%d",f[m][m]);
}
return 0;
}
请教了旁边zjy的大佬,他用的是广搜,但是这道题我自己编的广搜连样例都不了(菜),最后选择看了题解,发现对于每次答案的判断应该放在判断越界之后的if语句中,放在外面的话起到的优化作用其实并不大。然后恭喜你,有95分了,我也不知道为什么会第一个数据WA掉,下载了数据之后,特判了一下m=1的情况,直接输出0,这样你就成功AC了
#include
using namespace std;
int m,n;
int a[105][105];
bool b[105][105];
int mx[4]={-1,0,1,0};
int my[4]={0,-1,0,1};
int f[105][105];
inline void dfs(int x,int y,int sum,bool op){
if(sum>f[x][y]) return;
for(register int i=0;i<4;i++){
int nx=x+mx[i];
int ny=y+my[i];
if(sum>f[x][y]) return ;
if(nx>=1&&nx<=m&&ny>=1&&ny<=m&&b[nx][ny]==false){
if(a[nx][ny]==a[x][y]&&sum