2022.3.19
蓝书
AcWing 190. 字串变换
一开始用的是双向bfs,但只过了4个点,但是硬是要调,调了一下午还是没调出来。。后面换成普通bfs写发现也能过而且代码更少看来不能老是死磕,思路就是直接开队列按字符串的位置找能换的字串,如果最后换到和b一样说明成功了并且操作小于10说明成功了,否则输出-1。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100,INF=1e8;
string aa[10], bb[10];
string a, b;
int cnt;
struct node
{
string x;
int tt;
};
int bfs()
{
if(a==b)
return 0;
queue<node> que;
que.push({a, 0});
while(que.size())
{
auto t = que.front();
que.pop();
string s = t.x;
int tt = t.tt;
if(tt>=10)
return -1;
for (int i = 0; i < cnt;i++)
{
int pos = s.find(aa[i],0);
while(pos!=-1)
{
node t2;
t2.x = s;
t2.tt = tt + 1;
t2.x.replace(pos, aa[i].size(), bb[i]);
if(t2.x==b)
{
return t2.tt;
}
que.push(t2);
pos = s.find(aa[i], pos + 1);
}
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >>a>> b;
while(cin>>aa[cnt]>>bb[cnt])
{
cnt++;
}
int ans = bfs();
if(ans!=-1)
{
cout << ans << '\n';
}
else
cout << "NO ANSWER!" << '\n';
return 0;
}
AcWing 191. 天气预报
思路是枚举上下左右走1步还是2步九个状态,但是并不需要枚举每个格子是否超过一周没下雨,因为云是2x2的,也就是说云在的四个格子都会降雨,我们可以把四个格子看成是一个格子,这样只需要记录左上角的格子的状态就可以知道其他三个的状态,遍历的实时更新状态看是否合法,如果最后递归到了第n天说明是合法的。但是这题真的卡时间卡的离谱,t了不知道多少次,就算按题解的代码改了还是超时,其中注意一下记录状态的数组最好开bool,不然会爆内存,然后只有在里边循环的时候再把s1,s2,s3,s4写出来,写在循环外面会超时。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=365+10,INF=1e8;
bool vis[N][3][3][7][7][7][7];
int n,dx[9] = {0, 0, 0, 1, 2, 0, 0, -1, -2}, dy[9] = {0,-1, -2, 0, 0, 1, 2, 0, 0};
int a[N][5][5];
struct node
{
int d, x, y, s1, s2, s3, s4;
};
bool check(int d,int x,int y)
{
if(x >= 0 && x < 3 && y >= 0 && y < 3)
{
if(a[d][x][y]||a[d][x+1][y]||a[d][x][y+1]||a[d][x+1][y+1])
return 0;
else return 1;
}
return 0;
}
bool bfs()
{
queue<node> que;
que.push({1, 1, 1, 1, 1, 1, 1});
vis[1][1][1][1][1][1][1] = 1;
while(que.size())
{
auto t = que.front();
que.pop();
if(t.d==n)
return 1;
for (int i = 0; i < 9;i++)
{
int xx = t.x + dx[i], yy = t.y + dy[i];
int d = t.d;
if(!check(d+1,xx,yy)) continue;
int s1=t.s1,s2=t.s2,s3=t.s3,s4=t.s4;
if(xx==0&&yy==0)
{
s1 = 0;
}
else if(++s1==7)
continue;
if(xx==0&&yy==2)
{
s2 = 0;
}
else if(++s2==7)
continue;
if(xx==2&&yy==0)
{
s3 = 0;
}
else if(++s3==7)
continue;
if(xx==2&&yy==2)
{
s4 = 0;
}
else if(++s4==7)
continue;
if(vis[d+1][xx][yy][s1][s2][s3][s4])
continue;
vis[d + 1][xx][yy][s1][s2][s3][s4] = 1;
que.push({d + 1, xx, yy, s1, s2, s3, s4});
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
while(cin>>n&&n)
{
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n;i++)
{
for (int j = 0; j < 4;j++)
{
for (int k = 0; k < 4;k++)
{
cin >> a[i][j][k];
}
}
}
if(bfs())
cout << 1 << '\n';
else
cout << 0 << '\n';
}
return 0;
}
AcWing 195. 骑士精神
这道IDA咋看起来像bfs。对于本题我们可以换位思考,把问题转换成如何把输入的棋盘还原成原来的棋盘呢,我们现在找到当前可以移动的点,就是星点,然后枚举8个方向,直到两个棋盘相等,因为n范围只有15,所以我们可以使用迭代加深的方法,设定一个估价函数,一开始把估计函数设计成了当前的*点到原来棋盘星点的距离,发现超时了没设计好,于是看了题解的设计思路,估计函数设计成当前棋盘和原来棋盘不相等的点的个数。如果当前步数加上估价函数超过限制深度的话就回溯。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10,INF=1e8;
int dx[8] = {-1, -1, 1, 1, -2, -2, 2, 2}, dy[8] = {-2, 2, -2, 2, -1, 1, -1, 1};
char a[5][5]=
{'1','1','1','1','1',
'0','1','1','1','1',
'0','0','*','1','1',
'0','0','0','0','1',
'0','0','0','0','0'},b[5][5];
bool check()
{
for (int i = 0; i < 5;i++)
for (int j = 0; j < 5;j++)
if(a[i][j]!=b[i][j])
return 0;
return 1;
}
int dis()
{
int cnt = 0;
for (int i = 0; i < 5;i++)
for (int j = 0; j < 5;j++)
{
if(a[i][j]!=b[i][j]&&b[i][j]!='*')
cnt++;
}
return cnt;
}
bool dfs(int dep,int cnt)
{
if(cnt+dis()>dep)
return 0;
if(check())
return 1;
int x, y;
for (int i = 0; i < 5 ;i++)
for (int j = 0; j < 5;j++)
if(b[i][j]=='*')
x = i, y = j;
for (int i = 0; i < 8;i++)
{
int xx = x + dx[i], yy = y + dy[i];
if(xx<0||xx>=5||yy<0||yy>=5)
continue;
swap(b[xx][yy], b[x][y]);
if(dfs(dep, cnt + 1))return 1;
swap(b[xx][yy], b[x][y]);
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while (t--)
{
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
cin >> b[i][j];
int dep = 0;
while (dep <= 15)
{
if (dfs(dep,0))
break;
dep++;
}
if(dep<=15)
cout << dep << '\n';
else
cout << -1 << '\n';
}
return 0;
}