- poj1321 https://vjudge.net/problem/POJ-1321
题意:在一个n*n棋盘的指定位置放K个棋子,同一行同一列只能放一个,问方案数。
题解:标准dfs
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n, k;
int ans;
char mp[10][10];
int lie[10];
void dfs(int now, int num){
if(num == k){
ans++;
return;
}
if(now == n)
return;
dfs(now+1, num);
for(int i = 0; i < n; i++){
if(mp[now][i] == '#' && lie[i] == 0){
lie[i] = 1;
dfs(now+1, num+1);
lie[i] = 0;
}
}
}
int main(){
while(scanf("%d%d",&n, &k)==2){
if(n == -1 && k == -1)
break;
ans = 0;
for(int i = 0; i < 10; i++){
lie[i] = 0;
for(int j = 0; j < 10; j++){
mp[i][j] = '.';
}
}
for(int i = 0; i < n; i++){
scanf("%s", mp[i]);
}
dfs(0,0);
printf("%d\n", ans);
}
return 0;
}
2 .poj2251 https://vjudge.net/problem/POJ-2251
题意:三维的做迷宫问题
题解:bfs,比传统迷宫多了两个方向而已
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
int L, R, C;
char ma[35][35][35];
struct node{
int l,r,c;
int time;
}st, ed;
int dd[6][3] = { {1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1} };
void read(){
for(int i = 0; i < L; i++){
for(int j = 0; j < R; j++){
scanf("%s", ma[i][j]);
for(int k = 0; k < C; k++){
if(ma[i][j][k] == 'S'){
st.l = i, st.r = j, st.c = k;
}
if(ma[i][j][k] == 'E'){
ed.l = i, ed.r = j, ed.c = k;
}
}
}
getchar();
}
}
bool check(node x){
if(x.l<0||x.r<0||x.c<0||x.l>=L||x.r>=R||x.c>=C||ma[x.l][x.r][x.c]=='#')
return false;
return true;
}
int bfs(node st, node ed){
queue<node> Q;
Q.push(st);
while(!Q.empty()){
st = Q.front();
Q.pop();
if(st.l == ed.l && st.r == ed.r && st.c == ed.c){
return st.time;
}
for(int i = 0; i < 6; i++){
node q = st;
q.l += dd[i][0];
q.r += dd[i][1];
q.c += dd[i][2];
q.time++;
if(check(q)){
ma[q.l][q.r][q.c] = '#';
Q.push(q);
}
}
}
return -1;
}
int main(){
while(scanf("%d %d %d", &L, &R, &C)){
if(L==0 && R==0 && C==0)
break;
read();
int ans = bfs(st, ed);
if(ans == -1)
printf("Trapped!\n");
else{
printf("Escaped in %d minute(s).\n", ans);
}
}
return 0;
}
3 .poj3278 https://vjudge.net/problem/POJ-3278
题意:农夫抓牛,农夫从x到x-1, x+1, 2*x坐标所用时间都是1min,问从初始坐标到牛最少时间。
题解:对每个点,把它和x-1, x+1, x*2连边,在图上跑最短路即可。(dij, spfa)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 100005;
const int maxe = 300015;
int tot;
int head[maxn];
int dis[maxn];
int vis[maxn];
struct edge{
int v, w, next;
}e[maxe];
void add(int x, int y, int w){
e[++tot].v = y;
e[tot].w = w;
e[tot].next = head[x];
head[x] = tot;
}
int spfa(int st, int ed){
memset(dis, 0x3f, sizeof(dis));
queue<int> Q;
dis[st] = 0;
vis[st] = 1;
Q.push(st);
while(!Q.empty()){
int x = Q.front();
Q.pop();
vis[x] = 0;
for(int i = head[x]; i != -1; i = e[i].next){
int y = e[i].v;
int w = e[i].w;
if(dis[y] > dis[x] + w){
dis[y] = dis[x] + w;
if(!vis[y]){
Q.push(y);
vis[y] = 1;
}
}
}
}
printf("%d\n", dis[ed]);
}
int main(){
tot = -1;
int n, k;
scanf("%d%d", &n, &k);
memset(head, -1, sizeof(head));
add(0, 1, 1);
for(int i = 1; i < maxn; i++){
add(i, i+1, 1);
add(i, i-1, 1);
if(i < maxn/2-1)
add(i, 2*i, 1);
}
spfa(n ,k);
}
4 .poj3279 https://vjudge.net/problem/POJ-3279
题意:开关问题, 每次翻牌会使周围4个一起翻,问全部变成0的最少翻转方案。
题解:二进制压缩枚举第一行的翻转方案,往下递推,最后检查最后一行是否全为0.
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
int mp[20][20], st[20][20], v[20][20], res[20][20];
int ans = inf;
int dx[] = {0, -1, 1, 0, 0};
int dy[] = {1, 0, 0, -1, 0};
void flip(int x, int y){
int xx, yy;
for(int i = 0; i < 5; i++){
xx = x + dx[i];
yy = y + dy[i];
st[xx][yy] = !st[xx][yy];
}
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%d", &mp[i][j]);
}
}
int all = 1 << m;
for(int i = 0; i < all; i++){
int tmp = 0;
int flag = 0;
for(int j = 1; j <= n; j++){
for(int k = 1; k <= m; k++){
st[j][k] = mp[j][k];
}
}
for(int j = 0; j < 20; j++){
for(int k = 0; k < 20; k++){
v[j][k] = 0;
}
}
for(int j = 0; j < m; j++){
if( (i >> j) & 1 ){
flip(1, j+1);
v[1][j+1] = 1;
tmp++;
}
}
for(int j = 2; j <= n; j++){
for(int k = 1; k <= m; k++){
if(st[j-1][k]){
flip(j, k);
v[j][k] = 1;
tmp++;
}
}
}
for(int j = 1; j <= m; j++){
if(st[n][j]){
flag = 1;
break;
}
}
if(!flag && tmp < ans){
ans = tmp;
for(int j = 1; j <= n; j++){
for(int k = 1; k <= m; k++){
res[j][k] = v[j][k];
}
}
}
}
if(ans == inf){
printf("IMPOSSIBLE\n");
return 0;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
printf("%d ", res[i][j]);
}
printf("\n");
}
return 0;
}
5 .poj1426 https://vjudge.net/problem/POJ-1426
题意:对于一个数n(1 <= n <=200)找出一个只由0,1构成的十进制数,是它的倍数。(0倍不算)
题解:bfs,首位必然为1, 相当于依次填数,并检查是否为n的倍数。
吐槽:我的代码这么暴力竟然过了。。。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
void bfs(int n){
queue<long long> q;
q.push(1);
while(q.size()){
long long x = q.front();
q.pop();
if(x % n == 0){
printf("%lld\n", x);
return;
}
q.push(x*10);
q.push(x*10+1);
}
}
int main(){
int n;
while(scanf("%d", &n) && n){
bfs(n);
}
return 0;
}
6 .poj 3126 https://vjudge.net/problem/POJ-3126
题意:要求从一个素数(4位)变化为另一个素数(4位),每次变一个数字,中间过程也必须是素数,求最小变化次数?
题解:bfs,每次把能变成的素数入队,和最短路相似的方法res[x] = res[y] + 1更新答案。
代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
int T, n, m;
int ans;
int vis[10005];
int res[10005];
int prime[10005];
int v[10005];
int tt;
void Prime(){
memset(v, 0, sizeof(v));
tt = 0;
for(int i = 2; i <= 10000; i++){
if(!v[i]){
v[i] = i;
prime[++tt] = i;
}
for(int j = 1; j <= tt; j++){
if(v[i] < prime[j] || prime[j] > 10000 / i)
break;
v[i*prime[j]] = prime[j];
}
}
}
int bfs(){
memset(vis, 0, sizeof(vis));
memset(res, 0, sizeof(res));
queue<int> q;
int x, ttt, k;
int now[5];
q.push(n);
vis[n] = 1;
while(q.size()){
x = q.front();
q.pop();
now[4] = x % 10;
now[3] = (x / 10)%10;
now[2] = (x / 100) % 10;
now[1] = x/1000;
for(int i = 1; i <= 4; i++){
k = 0;
ttt = now[i];
if(i == 1)
k = 1;
for(int j = k; j <= 9; j++){
if(j == ttt)
continue;
now[i] = j;
int sum = now[1]*1000 + now[2]*100 + now[3]*10 + now[4];
if(v[sum] == sum && !vis[sum]){
q.push(sum);
vis[sum] = 1;
res[sum] = res[x] + 1;
}
if(sum == m)
return res[sum];
}
now[i] = ttt;
}
if(x == m)
return res[x];
}
return -1;
}
int main(){
Prime();
scanf("%d", &T);
while(T--){
scanf("%d %d", &n, &m);
ans = bfs();
if(ans == -1)
printf("Impossible\n");
else
printf("%d\n", ans);
}
return 0;
}
9 .fzu2150 https://vjudge.net/problem/FZU-2150
题意:大概就是在平面上任意选两个有草的位置点火,一分钟向周围扩散一圈,问把草烧光的最短时间。(记不清了,大概这意思)
题解:枚举这两个位置,bfs算出时间,取最小值即可
代码(略丑)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int T ,n, m;
char mp[20][20];
int v[20][20];
int ans;
int tot, cnt;
int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
struct node{
int x, y;
int time;
};
queue<node> q;
int bfs(){
int res = 0x3f3f3f3f;
while(!q.empty()){
node now = q.front();
q.pop();
cnt++;
if(cnt == tot){
res = now.time;
break;
}
for(int i = 0; i < 4; i++){
node ss = now;
ss.x += d[i][0];
ss.y += d[i][1];
ss.time++;
if(ss.x>=0&&ss.y>=0&&ss.x<n&&ss.y<m&&!v[ss.x][ss.y]&&mp[ss.x][ss.y]=='#'){
v[ss.x][ss.y] = 1;
q.push(ss);
}
}
}
while(!q.empty()) q.pop();
return res;
}
int main(){
int kase = 0;
scanf("%d", &T);
while(T--){
while(!q.empty()) q.pop();
tot = cnt = 0;
ans = 0x3f3f3f3f;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++){
scanf("%s", mp[i]);
for(int j = 0; j < m; j++){
if(mp[i][j] == '#')
tot++;
}
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
for(int r = 0; r < n; r++){
for(int c = 0; c < m; c++){
if(mp[i][j] == '#' && mp[r][c] == '#'){
cnt = 0;
memset(v, 0, sizeof(v));
node st1;
st1.x = i, st1.y = j, st1.time = 0;
v[i][j] = 1;
q.push(st1);
if(i != r || j != c){
node st2;
st2.x = r, st2.y = c, st2.time = 0;
q.push(st2);
v[r][c] = 1;
}
ans = min(ans, bfs());
}
}
}
}
}
printf("Case %d: ", ++kase);
if(ans == 0x3f3f3f3f)
printf("-1\n");
else
printf("%d\n", ans);
}
return 0;
}