我的做法是从上到下,从左到右扫描,每次扫描到一个可用的棋盘(‘#’),当前行和当前列都不能再有可用的棋盘(‘#’),然后进入下一层并往后继续扫描,一旦扫描到k个可用的棋盘(‘#’),就得到一种方案,递归得到所有的方案数即得到本题的解。
/***********************************************
* Author: fisty
* Created Time: 2015/1/27 21:45:57
* File Name : 1_A.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 10
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int n,k;
int ans;
int G[MAX_N][MAX_N];
int vis[MAX_N][MAX_N];
void dfs(int row, int col, int cnt){
if(cnt == k){
ans++;
return;
}else{
for(int x = row;x < n; x++){
for(int y = (x==row)?col:0;y < n; y++){
if(!vis[x][y] && G[x][y]){
//如果可行
//遍历下一个位置
int _vis[MAX_N][MAX_N];
//复制之前状态
for(int i = 0;i < n; i++){
for(int j = 0;j < n; j++){
_vis[i][j] = vis[i][j];
}
}
for(int j = 0;j < n; j++){
//清除下一个位置的标记
vis[j][y] = 1;
vis[x][j] = 1;
}
dfs(x, y, cnt+1);
//状态还原
for(int i = 0;i < n; i++){
for(int j = 0;j < n; j++){
vis[i][j] = _vis[i][j];
}
}
}
}
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
cin.tie(0);
ios::sync_with_stdio(false);
while(cin >> n >> k){
ans = 0;
if(n == -1 && k == -1) break;
memset(G, 0, sizeof(G));
memset(vis, 0, sizeof(vis));
for(int i = 0;i < n; i++){
for(int j = 0;j < n; j++){
char c;
cin >> c;
if(c == '#') G[i][j] = 1;
}
}
dfs(0,0,0);
cout << ans << endl;
}
return 0;
}
B - Dungeon Master
本题从‘S’出发,每次可以选择东南西北上下6个方向中可走的位置走一步(用dx,dy,dz数组控制),BFS可以确保第一个搜到‘E'的解为最少步数解。代码如下:
/***********************************************
* Author: fisty
* Created Time: 2015/1/28 9:14:26
* File Name : 1_B.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 35
char G[MAX_N][MAX_N][MAX_N];
int L, N, M;
int sx,sy,sz,gx,gy,gz; //起点,终点
int ans; //答案
int d[MAX_N][MAX_N][MAX_N]; //最短距离
//六个方向
const int dx[6] = {1,-1,0,0,0,0};
const int dy[6] = {0,0,1,-1,0,0};
const int dz[6] = {0,0,0,0,1,-1};
struct node{
int x, y, z;
node(int _x, int _y, int _z):x(_x),y(_y),z(_z){}
};
bool ok(int x, int y, int z){
//如果下一步可以走
if(d[x][y][z] == INF && x >= 0 && x < N && y >= 0 && y < M && z >= 0 && z < L && G[x][y][z] != '#')
return true;
return false;
}
int bfs(int x, int y, int z){
queue<node> que;
//while(que.size()) que.pop();
que.push(node(x,y,z));
d[x][y][z] = 0;
//bfs
while(que.size()){
node q = que.front(); que.pop();
if(G[q.x][q.y][q.z] == 'E') break; //如果可以逃出
for(int i = 0;i < 6; i++){
int _x = q.x + dx[i];
int _y = q.y + dy[i];
int _z = q.z + dz[i];
if(ok(_x, _y, _z)){
//如果可以下一步,入队,记录最短距离
que.push(node(_x, _y, _z));
d[_x][_y][_z] = d[q.x][q.y][q.z]+1;
}
}
}
return d[gx][gy][gz];
}
int main() {
//freopen("in.txt", "r", stdin);
cin.tie(0);
ios::sync_with_stdio(false);
while(cin >> L >> N >> M){
if(!L && !N && !M) break;
ans = INF;
sx = sy = sz = gx = gy = gz = 0;
//构图,确定终点和起点
memset(d, 0x3f, sizeof(d));
memset(G, 0, sizeof(G));
for(int k = 0;k < L; k++){
for(int i = 0;i < N; i++){
for(int j = 0;j < M; j++){
cin >> G[i][j][k];
if(G[i][j][k] == 'S'){
//起点
sx = i;sy = j; sz = k;
}
if(G[i][j][k] == 'E'){
//终点
gx = i;gy = j; gz = k;
}
}
}
}
ans = bfs(sx,sy,sz);
if(ans == INF){
//如果不能到达
printf("Trapped!\n");
}else{
//如果可以
printf("Escaped in %d minute(s).\n", ans);
}
}
return 0;
}
C - Catch That Cow
只不过是改成了一维的BFS,应该是更简单了。只不过只有往前一步,往后一步,和跳跃(2*X)。具体见代码~~
/***********************************************
* Author: fisty
* Created Time: 2015/1/28 11:19:54
* File Name : 1_C.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 100100
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int N, K; //出发,终点
int d[MAX_N]; //最短距离
const int dx[] = {-1,1,2}; //当为2时,变成X * d[i]
int bfs(){
queue<int> que;
que.push(N);
d[N] = 0; //初始化
while(que.size()){
int x = que.front(); que.pop();
if(x == K) break; //到达终点,结束
for(int i = 0;i < 3; i++){
int _x;
if(dx[i] == 2) _x = x * dx[i]; //跳跃
else _x = x + dx[i]; //前进或者后退一步
if(_x >= 0 && _x < 100001 && d[_x] == INF){
//符合条件,往下走
d[_x] = d[x] + 1;
que.push(_x);
}
}
}
return d[K];
}
int main() {
//freopen("in.txt", "r", stdin);
cin.tie(0);
ios::sync_with_stdio(false);
while(cin >> N >> K){
memset(d, 0x3f, sizeof(d));
int ans = bfs();
cout << ans << endl;
}
return 0;
<span style="color:#FF0000;">}
</span>
D -
Fliptile
给定一个N*M的网格,每个网格里有一个数字,0或者1,要求你翻转尽量少的网格,使得所有网格的数字都变为0,对于某一个网格进行翻转操作时,与它有公共边的网格全部会被翻转。
枚举第一行的状态,只要第一行的状态确定了,可以往下推出其余状态。
/***********************************************
* Author: fisty
* Created Time: 2015/1/28 15:43:04
* File Name : 1_D.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 20
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int M,N;
int a[MAX_N][MAX_N], b[MAX_N][MAX_N], ans[MAX_N][MAX_N];
bool check(int s){
for(int i = 0;i < N; i++){
//更新第一行
if(s & (1<<i)){
ans[0][i] = 1;
b[0][i] ^= 1;
if(1 < M) b[1][i] ^= 1; //下
if(i-1 >= 0) b[0][i-1] ^= 1; //左
if(i+1 < M) b[0][i+1] ^= 1; //右
}
}
for(int i = 1;i < M; i++){
for(int j = 0;j < N; j++){
if(b[i-1][j]){
ans[i][j] = 1;
b[i][j] ^= 1;
//更新上下左右
b[i-1][j] ^= 1;
if(i+1 < M) b[i+1][j] ^= 1;
if(j-1 >= 0) b[i][j-1] ^= 1;
if(j+1 < N) b[i][j+1] ^= 1;
}
}
}
for(int i = 0;i < N; i++){
if(b[M-1][i]) return false;
}
return true;
}
void print(){
for(int i = 0;i < M; i++){
for(int j = 0;j < N; j++){
printf("%d%c", ans[i][j], (j == N-1)?'\n': ' ');
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
//cin.tie(0);
//ios::sync_with_stdio(false);
scanf("%d%d", &M, &N);
for(int i = 0;i < M; i++){
for(int j = 0;j < N; j++){
scanf("%d", &a[i][j]);
}
}
int ok = 0;
for(int i = 0;i < (1<<N); i++){
//枚举第一行的所有状态
memcpy(b, a, sizeof(a));
memset(ans, 0, sizeof(ans));
if(check(i)){
ok = 1;
print();
break;
}
}
if(!ok)
printf("IMPOSSIBLE\n");
return 0;
}
E - Find The Multiple
在1~200的数据里,结果不会有100位的。。所以用unsigned long long就可以存下
直接搜第k*10和k*10+1就可以
/***********************************************
* Author: fisty
* Created Time: 2015/1/28 16:55:14
* File Name : 1_E.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<int, int> P;
bool ok;
void dfs(ULL k, int n, int dep){
if(ok) //当已经查找到返回
return ;
if(!(k % n)){
cout << k << endl; //找到输出
ok = true;
return ;
}
if(dep == 19){
//最大就19层
//递归回溯
return ;
}
//想要数字里只存在1和0只递归这两种就可以
dfs(k * 10, n, dep+1); //k * 10
dfs(k * 10 + 1, n, dep+1); //k * 10 + 1
}
int main(){
//freopen("in.txt", "r", stdin);
//cin.tie(0);
//ios::sync_with_stdio(false);
int n;
while(cin >> n){
if(!n) break;
ok = false;
dfs(1, n, 0);
}
return 0;
}
F - Prime Path
1.先将两个数每一位进行分离,保存起来
2.用bfs来解,把4位数字看成一个状态,每一位数可以变换9次,而且有4位数,每变换一个位,检查是否是素数并且没有被访问过,如果是,放入队列。如果可以达到目标状态,那么输出最少的步数,直到队列为空也没有找到,返回无解
J - Fire!
需要两个BFS,第一个寻找每块空地被蔓延到的时间,第二个寻找人离开这里的最短路径,如果必须被烧到则输出IMPOSSIBLE
需要注意的就是人只有一个出发点,但是可以有N个着火点,N也可以为0,WA了无数次总结出来的。。
我这里直接用的G[MAX_N][MAX_N]来保存的地图。如果是墙,则为-1,是空地设置为INF,第一次bfs之后,G里面保存的是火到达每一个空地的时间(墙还是-1)
所以在第二次bfs人逃跑的时候,只要这个人可以赶在这个点着火之前通过就可以
设置一个数组pre[i] 表示i的路径前驱是pre[i],只不过类型是坐标形式。pre得到的是从终点到起点的路径,输出需要借助栈反序
/***********************************************
* Author: fisty
* Created Time: 2015/1/29 12:53:29
* File Name : 1_K.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define MAX_N 30
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
int maze[10][10];
int d[MAX_N][MAX_N];
map<P, P> pre; //i的前驱是pre[i];
const int dx[] = {0,0,-1,1};
const int dy[] = {1,-1,0,0};
void bfs(){
memset(d, 0x3f, sizeof(d));
queue<P> que;
que.push(P(0, 0));
d[0][0] = 0;
while(que.size()){
P q = que.front(); que.pop();
for(int i = 0;i < 4; i++){
int x = q.first + dx[i];
int y = q.second + dy[i];
if(!maze[x][y] && d[x][y] == INF && x >=0 && x < 5 && y >= 0 && y < 5){
d[x][y] = d[q.first][q.second] + 1;
que.push(P(x, y));
//路径前驱
pre[P(x, y)] = P(q.first, q.second);
}
}
}
}
int main() {
//freopen("in.txt", "r", stdin);
cin.tie(0);
ios::sync_with_stdio(false);
memset(maze, 0, sizeof(maze));
for(int i = 0;i < 5; i++){
for(int j = 0;j < 5; j++){
cin >> maze[i][j];
}
}
bfs();
//路径输出
P s(4,4);
stack<P> _stack;
while(!(s.first == 0 && s.second == 0)){
_stack.push(P(s.first, s.second));
s = pre[s];
}
_stack.push(P(0, 0));
while(_stack.size()){
P ans = _stack.top(); _stack.pop();
cout <<"("<< ans.first <<", "<< ans.second <<")"<<endl;
}
//cout << d[4][4] << endl;
return 0;
}
M-非常可乐
就是用队列模拟倒水的情况。。
若s中有水,那么有两种情况,可以给n倒,也可以给m倒
1.给n倒 有两种情况
A.可以倒满
B.倒不满
2.给m倒 有两种情况
A.可以倒满
B.倒不满
若n中有水。。m中有水,还是上面相同的倒法,输出最少步数
1.用BFS分别找出‘Y’和‘M’到每个‘@’点的最小时间。
2.枚举每个‘@’的位置,并找出到‘Y’点、‘M’点之和的最短距离。
3.输出第2步求的的最短距离乘以11.
/***********************************************
* Author: fisty
* Created Time: 2015/1/29 16:29:39
* File Name : 1_N.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define MAX_N 220
int n, m;
char G[MAX_N][MAX_N];
P KFC[MAX_N];
int Y_d[MAX_N][MAX_N];
int M_d[MAX_N][MAX_N];
int d[MAX_N][MAX_N];
const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};
void bfs(int x, int y,int flag){
memset(d, 0x3f, sizeof(d));
d[x][y] = 0;
queue<P> que;
que.push(P(x, y));
while(que.size()){
P q = que.front(); que.pop();
for(int i = 0;i < 4; i++){
int _x = q.first + dx[i];
int _y = q.second + dy[i];
if(d[_x][_y] == INF && _x >= 0 && _x < n && _y >= 0 && _y < m && G[_x][_y] != '#'){
d[_x][_y] = d[q.first][q.second] + 1;
que.push(P(_x, _y));
}
}
}
if(flag){
memcpy(M_d, d, sizeof(d));
}else{
memcpy(Y_d, d, sizeof(d));
}
}
int main() {
//freopen("in.txt", "r", stdin);
cin.tie(0);
ios::sync_with_stdio(false);
while(cin >> n >> m){
memset(Y_d, 0x3f, sizeof(Y_d));
memset(M_d, 0x3f, sizeof(M_d));
for(int i = 0;i < n; i++){
for(int j = 0;j < m; j++){
cin >> G[i][j];
}
}
int cnt = 0; //KFC' count
for(int i = 0;i < n; i++){
for(int j = 0;j < m; j++){
if(G[i][j] == 'Y'){
bfs(i, j, 0);
}
if(G[i][j] == 'M'){
bfs(i, j, 1);
}
if(G[i][j] == '@'){
KFC[cnt].first = i;
KFC[cnt++].second = j;
}
}
}
int ans = INF;
for(int i = 0;i < cnt; i++){
ans = min(ans, M_d[KFC[i].first][KFC[i].second] + Y_d[KFC[i].first][KFC[i].second]);
}
cout << ans * 11 << endl;
}
return 0;
}