一句话题意: 棋盘大小为 h × w h \times w h×w,有一个王停在 ( 1 , 1 ) (1,1) (1,1)。每一步可以走到八联通的格子之一。构造一种方案,使得王经过所有格子恰好一次,并停在 ( a , b ) (a, b) (a,b)。 1 ≤ h , w ≤ 100 1 \leq h, w \leq 100 1≤h,w≤100。
分析: 一道很神奇的构造题, 感觉是一道大分讨,但是题解用特殊的方法可以让程序只有短短 34 34 34 行。
我们首先考虑当只有两行时该怎么做:
因为我们的移动方式非常多样,我们可以通过 下-上-下的方式遍历到 [ 1 , b − 1 ] [1, b-1] [1,b−1] 列的所有格子。然后到第 b b b 列我们显然可以直接到达 不是 ( a , b ) (a,b) (a,b) 的那个位置,然后我们只需要跳到 ( 1 , b + 1 ) (1, b + 1) (1,b+1) 后一直沿着第一行走,然后在一直沿着第二行走到 ( 2 , b + 1 ) (2, b + 1) (2,b+1) 后直接跳到 ( a , b ) (a,b) (a,b) 就好了。可以写这么一份代码:
if(h == 2){//只有两行
for(int i = 1; i < b; i++) ret.pb(mp(1, i)), ret.pb(mp(2, i));
ret.pb(mp(3 - a, b));
for(int i = b + 1; i <= w; i++) ret.pb(mp(1, i));
for(int i = w; i > b; i--) ret.pb(mp(2, i));
ret.pb(mp(a, b));
}
当行数不是 2 2 2 但列数是 2 2 2 时,我们可以把矩形行列交换,相当翻转了一下。然后按照上述方法做就行了。最后记得把路径上的点横纵坐标都交换一下。
if(w == 2){
vector< PII > res;
res = solve(w, h, b, a);
for(auto &x : res) swap(x.first, x.second);
ret.insert(ret.end(), res.begin(), res.end());
}
更一般的,我们考虑如果行数也不是
2
2
2,并且列数也不是
2
2
2 该怎么做:我们可以一列一列的消,将大问题转化成小问题。怎么构造方案可以一列一列的消除呢?
如果绿色格子里没有终点 ( a , b ) (a, b) (a,b) ,那么我们显然可以依次走绿色的格子,然后相当于是从 L L L 形的右下侧开始一个新的子问题。如果绿色格子里面有终点呢? 最神奇的一步:我们可以把行列交换,这时候终点一定不在交换后的地图的绿色格子里面了。那么问题就得到了解决。
CODE:
#include<bits/stdc++.h>//好强的构造题啊 一直调转矩阵转化成子问题就好了
#define pb push_back
#define mp make_pair
#define PII pair< int, int >
using namespace std;// 两行的可以搞, 两列的可以看做是反过来
int h, w, a, b;
vector< PII > res;
vector< PII > solve(int h, int w, int a, int b){//问题:从(1, 1) 出发, 在 h 行 w 列的图上,到 (a, b)
vector< PII > ret;
if(h == 2){//只有两行
for(int i = 1; i < b; i++) ret.pb(mp(1, i)), ret.pb(mp(2, i));
ret.pb(mp(3 - a, b));
for(int i = b + 1; i <= w; i++) ret.pb(mp(1, i));
for(int i = w; i > b; i--) ret.pb(mp(2, i));
ret.pb(mp(a, b));
}
else if((w == 2) || (b == 1) || (a == h && b == 2)){//需要调转矩阵
vector< PII > res;
res = solve(w, h, b, a);
for(auto &x : res) swap(x.first, x.second);
ret.insert(ret.end(), res.begin(), res.end());
}
else{//不需要调转矩阵
for(int i = 1; i <= h; i++) ret.pb(mp(i, 1));
vector< PII > res = solve(h, w - 1, h + 1 - a, b - 1);
for(auto &x : res) x.first = (h + 1 - x.first), x.second++;
ret.insert(ret.end(), res.begin(), res.end());
}
return ret;
}
int main(){
cin >> h >> w >> a >> b;
res = solve(h, w, a, b);
for(auto x : res) cout << x.first << ' ' << x.second << endl;
return 0;
}