帶你飛專題1
學習算法
1.poj1321
- 類似8皇后,使用遞歸解
#include <iostream>
using namespace std;
const int N = 10;
char g[N][N];
bool cols[N];
int n=0,k=0;
int ans;
void dfs(int col,int num){
if(col == n){
if(num == k) ans ++;
return;
}
for(int i=0;i<n;i++){
if(!cols[i] && g[col][i] == '#'){
cols[i] = true;
dfs(col+1,num+1);
cols[i] = false;
}
}
dfs(col+1,num);
}
int main() {
while (cin >> n >> k)
{
if(n == -1 && k == -1) break;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin >> g[i][j];
}
}
ans = 0;
dfs(0,0);
cout << ans << '\n';
}
}
2.poj2251
- 3D BFS,因為有x,y,z所以用class存取比較方便,也可以用tuple
- 每次走過都將mp設為
#
,避免重複走導致TLE
#include <iostream>
#include <stdio.h>
#include <queue>
using namespace std;
int l, r, c;
char mp[31][31][31]; // z x y
int vis[31][31][31];
int s_x, s_y, s_z; // start
int e_x, e_y, e_z; // end
int d_x[6] = {0, 0, -1, 0, 1, 0};
int d_y[6] = {0, 0, 0, 1, 0, -1};
int d_z[6] = {1, -1, 0, 0, 0, 0};
class Point
{
public:
Point(int x = 0, int y = 0, int z = 0) : _x(x), _y(y), _z(z) {};
int _x, _y, _z;
};
int bfs()
{
queue<Point> q;
q.push(Point(s_x, s_y, s_z));
vis[s_z][s_x][s_y] = 0;
while (q.size())
{
Point p = q.front();
q.pop();
if (p._x == e_x && p._y == e_y && p._z == e_z)
return vis[e_z][e_x][e_y];
for (int i = 0; i < 6; i++)
{
int n_x = p._x + d_x[i];
int n_y = p._y + d_y[i];
int n_z = p._z + d_z[i];
if (mp[n_z][n_x][n_y] != '#' && n_x >= 0 && n_x < r && n_y >= 0 && n_y < c && n_z >= 0 && n_z < l )
{
q.push(Point(n_x, n_y, n_z));
vis[n_z][n_x][n_y] = vis[p._z][p._x][p._y] + 1;
mp[n_z][n_x][n_y] = '#';
}
}
}
return -1;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
while (cin >> l >> r >> c)
{
if (l == 0 && r == 0 && c == 0)
return 0;
for (int i = 0; i < l; i++)
{
for (int j = 0; j < r; j++)
{
for (int k = 0; k < c; k++)
{
cin >> mp[i][j][k];
if (mp[i][j][k] == 'S')
{
s_z = i;
s_x = j;
s_y = k;
}
else if (mp[i][j][k] == 'E')
{
e_z = i;
e_x = j;
e_y = k;
}
}
}
}
memset(vis,-1,sizeof(vis));
int ans = bfs();
ans == -1 ? printf("Trapped!\n") : printf("Escaped in %d minute(s).\n", ans);
}
}
3.poj3278
dis[now]+1
代表從現在節點移動到下一個節點的最短距離,下一個節點有可能是dis[now+1]/dis[now-1]/dis[now*2]
- 如果說是小於的話,就跟新值
#include <iostream>
#include <queue>
#include <string.h>
using namespace std;
const int maxn = 100000;
int n,k,dis[maxn+1],now;
queue<int> q;
int main(){
while(cin >> n >> k){
memset(dis,0x3f,sizeof(dis));
q.push(n);
dis[n] = 0;
while(q.size()){
now = q.front();
q.pop();
if(now + 1 <= maxn && dis[now]+1 < dis[now+1]){
q.push(now+1);
dis[now+1] = dis[now]+1;
}
if(now-1 >= 0 && dis[now]+1 < dis[now-1]){
q.push(now-1);
dis[now-1] = dis[now]+1;
}
if(now*2 <= maxn && dis[now]+1 < dis[now*2]){
q.push(now*2);
dis[now*2] = dis[now]+1;
}
}
cout << dis[k] << '\n';
}
}
4.poj3279
- 由於需要枚舉翻轉次數有可能會造成太大的時間消耗,因此使用狀態壓縮解決
- 狀態枚舉
1 << m
表示將2^m
種可能性全部枚舉。對於每個可能的 i,它代表著第一行的翻轉情況。
for (int i = 0; i < (1 << m); i++) {
slove(i);
}
- 狀態處理
- 通過 `x >> i & 1`` 來檢查 x 的第 i 位是否為 1。如果是 1,則翻轉第 0 行的第 i 列。
if ((x >> i) & 1) {
reverse_(0, i);
}
- 後續處理
- 當處理完第一行的翻轉後,後續每一行的翻轉決定於上一行是否有 1。如果上一行的某個格子是 1,那麼對應的當前行的格子就必須翻轉,這樣才能將上一行的格子變成 0
if (temp[i - 1][j]) {
reverse_(i, j);
}
#include <cstring>
#include <stdio.h>
using namespace std;
const int INF = 0x3f3f3f;
const int N = 15 + 5;
int board[N][N], temp[N][N], vis[N][N], ans[N][N];
int n, m;
int min_step_ = INF;
int dict[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
void reverse_(int u, int v) {
vis[u][v] = 1;
temp[u][v] ^= 1;
for (int i = 0; i < 4; i++) {
int x = u + dict[i][0];
int y = v + dict[i][1];
if (x >= 0 && x < n && y >= 0 && y < m) {
temp[x][y] ^= 1;
}
}
}
bool check() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (temp[i][j] == 1)
return false;
}
}
return true;
}
void slove(int x) {
memcpy(temp, board, sizeof(board));
memset(vis, 0, sizeof(vis));
int cnt = 0;
for (int i = 0; i < m; i++) {
// 狀態壓縮
if ((x >> i) & 1) {
cnt++;
reverse_(0, i);
}
}
for (int i = 1; i < n; i++) {
for (int j = 0; j < m; j++) {
if (temp[i - 1][j] == 1) {
cnt++;
reverse_(i, j);
}
}
}
if (check() && cnt < min_step_) {
min_step_ = cnt;
memcpy(ans, vis, sizeof(vis));
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &board[i][j]);
}
}
// 枚舉
for (int i = 0; i < (1 << m); i++) {
slove(i);
}
if (min_step_ == INF) {
printf("IMPOSSIBLE");
} else {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m - 1; j++) {
printf("%d ", ans[i][j]);
}
printf("%d\n", ans[i][m - 1]);
}
}
}