ABC—D - 8 Puzzle on Graph
题意:
有一个空位,利用空位将将矩阵还原
思路:
突然想起来一道典中典的搜索题没有写博客
经典八数码问题
将
3
∗
3
3*3
3∗3 的矩阵转化为字符串表示一种状态
最终状态即为
123456789
123456789
123456789
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
vector <int> v[10];
void work()
{
cin >> m;
for(int i = 1; i <= m; ++i){
int a, b;cin >> a >> b;
v[a].push_back(b);
v[b].push_back(a);
}
string s = "@999999999";
for(int i = 1, x; i <= 8; ++i){
cin >> x;
s[x] = i + '0';
}
queue <string> q;
unordered_map<string, int> dis;
q.push(s);
dis[s] = 0;
while(!q.empty()){
string now = q.front();q.pop();
int pos;
for(int i = 1; i <= 9; ++i) if(now[i] == '9') pos = i;
for(auto to : v[pos]){
string t = now;
swap(t[to], t[pos]);
if(dis.count(t)) continue;
dis[t] = dis[now] + 1;
q.push(t);
}
}
if(!dis.count("@123456789")) cout << -1;
else cout << dis["@123456789"];
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}
问题 D: 【宽搜入门】魔板
思路:
模拟bfs即可
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int x;
string st = "12345678";
string A(string t){
for(int j = 0; j < 4; ++j) swap(t[j], t[7-j]);
return t;
}
string B(string t){
char x = t[3];t[3] = t[2]; t[2] = t[1]; t[1] = t[0]; t[0] = x;
x = t[4];t[4] = t[5], t[5] = t[6], t[6] = t[7]; t[7] = x;
return t;
}
string C(string t){// now --> t
string now = t;
t[1] = now[6]; t[2] = now[1]; t[5] = now[2]; t[6] = now[5];
return t;
}
void work()
{
string ed = "";
ed += x + '0';
for(int i = 1; i <= 7; ++i){
cin >> x;ed += (x + '0');
}
unordered_map <string, int> dis;
unordered_map <string, string> pre;
queue <string> q;
q.push(st);
dis[st] = 0;
while(!q.empty())
{
string now = q.front();q.pop();
for(int i = 0; i < 3; ++i){
string t = now;
if(i == 0){// A
t = A(t);
}
else if(i == 1){// B
t = B(t);
}
else {// C
t = C(t);
}
if(!dis.count(t) || dis[t] > dis[now] + 1){
q.push(t);
dis[t] = dis[now] + 1;
pre[t] = now;
}
}
}
string now = ed;
string ans;
while(now != st)
{
string t = pre[now];
// A
if(A(t) == now){
ans += "A";
now = t;
}
else if(B(t) == now){
ans += "B";
now = t;
}
else {
ans += "C";
now = t;
}
}
cout << dis[ed] << endl;
reverse(all(ans));
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
while(cin >> x)
work();
return 0;
}
46届沈阳 J题
思路:
核心思路:
对
a
,
b
a,b
a,b 转化坐标系
将序列
a
a
a 转化为
0000
0000
0000,对
b
b
b 进行相应扭动
假设
a
=
2345
,
b
=
1234
a=2345,b=1234
a=2345,b=1234
2
2
2 向下转两个变成
0
0
0,
1
1
1 也向下转两个则变成
9
9
9,即
(
1
−
2
+
10
)
%
10
(1-2+10)\%10
(1−2+10)%10
可以推出
b
i
=
(
b
i
−
a
i
+
10
)
%
10
b_i=(b_i-a_i+10)\%10
bi=(bi−ai+10)%10
对
b
b
b 序列每一位转化即可
状态共
1
0
4
10^4
104 种,
b
f
s
bfs
bfs 预处理即可
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
unordered_map <string, int> dis;
queue <string> q;
vector <string> v;
string change(string now, string d, int k){
for(int i = 0; i < 4; ++i){
if(d[i] == '0') continue;
int x = now[i] - '0', y = d[i] - '0';
x = (x + k * y + 10) % 10;
now[i] = x + '0';
}
return now;
}
void init(){
v.push_back("1000");v.push_back("0100");v.push_back("0010");v.push_back("0001");
v.push_back("1100");v.push_back("0110");v.push_back("0011");v.push_back("1110");
v.push_back("0111");v.push_back("1111");
string st = "0000";
dis[st] = 0;
q.push(st);
while(!q.empty())
{
string now = q.front();q.pop();
for(auto d : v){
string t = change(now, d, 1);
if(!dis.count(t)) {
dis[t] = dis[now] + 1;
q.push(t);
}
t = change(now, d, -1);
if(!dis.count(t)) {
dis[t] = dis[now] + 1;
q.push(t);
}
}
}
}
void work()
{
int x, y;cin >> x >> y;
string ans = "";
ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10, y /= 10;
ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10; y /= 10;
ans += (y % 10 - x % 10 + 10) % 10 + '0'; x /= 10; y /= 10;
ans += (y % 10 - x % 10 + 10) % 10 + '0';
reverse(all(ans));
cout << dis[ans] << endl;
}
int main()
{
ios::sync_with_stdio(0);
init();
int TT;cin>>TT;while(TT--)
work();
return 0;
}
172. 立体推箱子
思路:
这种题目难就难在描述状态上
设三元组
(
x
,
y
,
l
i
e
)
(x,y,lie)
(x,y,lie) 代表一个状态,其中
l
i
e
=
0
lie=0
lie=0 表示长方体立在
(
x
,
y
)
(x,y)
(x,y);
l
i
e
=
1
lie=1
lie=1 表示长方体横向躺着,左半部分在
(
x
,
y
)
(x,y)
(x,y);
l
i
e
=
2
lie=2
lie=2 表示长方体纵向躺着,上半部分在
(
x
,
y
)
(x,y)
(x,y),并用数组
d
i
s
[
x
]
y
]
[
l
i
e
]
dis[x]y][lie]
dis[x]y][lie] 记录从起点状态到达每个状态的最小步数
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 5e2 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
// 最核心的部分
const int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};// 作参照
const int next_x[3][4] = {{0, 0, -2, 1}, {0, 0, -1, 1}, {0, 0, -1, 2}};
const int next_y[3][4] = {{-2, 1, 0, 0}, {-1, 2, 0, 0}, {-1, 1, 0, 0}};
const int next_lie[3][4] = {{1, 1, 2, 2}, {0, 0, 1, 1}, {2, 2, 0, 0}};
// next_x[i][j] 表示 lie = i 时,朝方向 j 滚动 x后的变化情况
char mp[maxn][maxn];
int dis[maxn][maxn][3];// 状态答案数组
struct node{
int x, y, lie;
bool operator==(const node &B)const{
if(x == B.x && y == B.y && lie == B.lie) return 1;
return 0;
}
};
queue <node> q;
node st, ed;
bool check(int x, int y){
if(x < 1 || y < 1 || x > n || y > m) return 0;
return 1;
}
bool check(node d){
if(!(d.x, d.y)) return 0;
if(mp[d.x][d.y] == '#') return 0;
if(d.lie == 0 && mp[d.x][d.y] == 'E') return 0;
if(d.lie == 1 && (mp[d.x][d.y+1] == '#' || !check(d.x, d.y + 1))) return 0;
if(d.lie == 2 && (mp[d.x+1][d.y] == '#' || !check(d.x + 1, d.y))) return 0;
return 1;
}
void bfs(){
while(!q.empty()) q.pop();
q.push(st);
dis[st.x][st.y][st.lie] = 0;
while(!q.empty()){
node now = q.front();q.pop();
for(int i = 0; i < 4; ++i){
node next;
next.x = now.x + next_x[now.lie][i];
next.y = now.y + next_y[now.lie][i];
next.lie = next_lie[now.lie][i];
if(!check(next)) continue;
if(dis[next.x][next.y][next.lie] == -1){
dis[next.x][next.y][next.lie] = dis[now.x][now.y][now.lie] + 1;
q.push(next);
if(next == ed) return;
}
}
}
}
void work()
{
mem(dis, -1);
for(int i = 1; i <= n; ++i){
cin >> (mp[i] + 1);
for(int j = 1; j <= m; ++j){
if(mp[i][j] == 'O') ed = {i, j, 0};
}
}
for(int i = 1; i <= n; ++i){
bool f = 0;
for(int j = 1; j <= m; ++j){
if(mp[i][j] == 'X'){
f = 1;
if(i - 1 >= 1 && mp[i-1][j] == 'X') {
st = {i-1, j, 2};break;
}
if(i + 1 <= n && mp[i+1][j] == 'X') {
st = {i, j, 2};break;
}
if(j - 1 >= 1 && mp[i][j-1] == 'X'){
st = {i, j - 1, 1};break;
}
if(j + 1 <= m && mp[i][j+1] == 'X') {
st = {i, j, 1};break;
}
st = {i, j, 0};break;
}
}
if(f) break;
}
bfs();
int ans = dis[ed.x][ed.y][ed.lie];
if(ans == -1) cout << "Impossible\n";
else cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
while(cin >> n >> m && n && m)
work();
return 0;
}
173. 矩阵距离
思路:
显然逆向思维,从所有的
1
1
1 开始跑更新最短路就好了
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 1e3 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};
char mp[maxn][maxn];
int dis[maxn][maxn];
struct node{
int x, y, step;
};
queue <node> q;
bool check(int x, int y){
if(x < 1 || y < 1 || x > n || y > m) return 0;
return 1;
}
void bfs(){
while(!q.empty()){
node now = q.front();q.pop();
for(int i = 0; i < 4; ++i){
int x = now.x + dx[i], y = now.y + dy[i];
if(!check(x, y)) continue;
if(dis[x][y] > now.step + 1){
dis[x][y] = now.step + 1;
q.push({x, y, now.step + 1});
}
}
}
}
void work()
{
mem(dis, 0x3f);while(q.size()) q.pop();
cin >> n >> m;
for(int i = 1; i <= n; ++i) cin >> (mp[i] + 1);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j){
if(mp[i][j] == '1') q.push({i, j, 0}), dis[i][j] = 0;
}
bfs();
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cout << dis[i][j] << " \n"[j==m];
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}