- 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;
}
7 .poj3087 https://vjudge.net/problem/POJ-3087
题意:按题目要求洗牌,问能不能洗成指定模样,能则输出步数,不能输出-1。
题解:就是模拟题,用map记录一下出现过没
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
using namespace std;
int T, c;
char s1[205], s2[205], s12[205];
char an[205];
int main(){
int kase = 0;
scanf("%d", &T);
while(T--){
map<string, int> mp;
int cnt = 0;
scanf("%d", &c);
scanf("%s", s1);
scanf("%s", s2);
scanf("%s", an);
mp[an] = 1;
while(1){
int m = 0;
for(int i = 0; i < c; i++){
s12[m] = s2[i];
m++;
s12[m] = s1[i];
m++;
}
s12[m] = '\0';
cnt++;
if(mp[s12] && strcmp(s12, an)){
printf("%d -1\n", ++kase);
break;
}
if(!strcmp(s12, an)){
printf("%d %d\n", ++kase, cnt);
break;
}
mp[s12] = 1;
for(int i = 0; i < c; i++){
s1[i] = s12[i];
s2[i] = s12[i+c];
}
s1[c] = '\0';
s2[c] = '\0';
}
}
return 0;
}
8 .poj3414 https://vjudge.net/problem/POJ-3414
题解:倒水问题, 记录路径, bfs
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
int A, B, C;
int v[105][105];
struct node{
int a, b;
int s, flag;
int pre;
}cu[105*105];
int t[105*105];
int cnt;
int bfs(){
queue<node> q;
node now;
now.a = now.b = 0;
now.pre = -1;
now.s = 0;
q.push(now);
v[0][0] = 1;
while(q.size()){
cnt++;
cu[cnt] = q.front();
q.pop();
for(int i = 1; i <= 6; i++){
if(i == 1){//FILL(1)
now.a = A;
now.b = cu[cnt].b;
now.flag = 1;
}
else if(i == 2){//FILL(2)
now.a = cu[cnt].a;
now.b = B;
now.flag = 2;
}
else if(i == 3){//DROP(1)
now.a = 0;
now.b = cu[cnt].b;
now.flag = 3;
}
else if(i == 4){//DROP(2)
now.a = cu[cnt].a;
now.b = 0;
now.flag = 4;
}
else if(i == 5){//POUR(1,2);
if(cu[cnt].a + cu[cnt].b <= B){
now.b = cu[cnt].a + cu[cnt].b;
now.a = 0;
}
else{
now.a = cu[cnt].a + cu[cnt].b - B;
now.b = B;
}
now.flag = 5;
}
else if(i == 6){//POUR(2,1)
if(cu[cnt].a + cu[cnt].b <= A){
now.a = cu[cnt].a + cu[cnt].b;
now.b = 0;
}
else{
now.b = cu[cnt].a + cu[cnt].b - A;
now.a = A;
}
now.flag = 6;
}
if(!v[now.a][now.b]){
v[now.a][now.b] = 1;
now.s = cu[cnt].s + 1;
now.pre = cnt;
q.push(now);
}
if(now.a == C || now.b == C){
int step = now.s;
t[step] = now.flag;
return step;
}
}
}
return -1;
}
int main(){
scanf("%d%d%d", &A,&B,&C);
int ans = bfs();
if(ans == -1){
printf("impossible\n");
}
else{
int last = cnt;
printf("%d\n", ans);
for(int i = ans-1; i >= 1; i--){
t[i] = cu[last].flag;
last = cu[last].pre;
}
for(int i = 1; i <= ans; i++){
if(t[i] == 1) printf("FILL(1)\n");
else if(t[i] == 2) printf("FILL(2)\n");
else if(t[i] == 3) printf("DROP(1)\n");
else if(t[i] == 4) printf("DROP(2)\n");
else if(t[i] == 5) printf("POUR(1,2)\n");
else if(t[i] == 6) printf("POUR(2,1)\n");
}
}
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;
}
11 .poj3984 https://vjudge.net/problem/POJ-3984
题解:记录路径的bfs
#include <iostream>
#include <cstdio>
#include <queue>
#include <stack>
#include <cstring>
using namespace std;
int mp[10][10];
int v[10][10];
int dx[] = {0, 1, -1, 0};
int dy[] = {1, 0, 0, -1};
struct node{
int x, y;
int s, l[30];
};
node bfs(){
int xx, yy;
queue<node> q;
node now, x;
x.x = 0, x.y = 0, x.s = 0;
q.push(x);
v[0][0] = 1;
while(q.size()){
x = q.front();
q.pop();
if(x.x == 4 && x.y == 4){
return x;
}
for(int i = 0; i < 4; i++){
xx = x.x + dx[i];
yy = x.y + dy[i];
if(xx >= 0 && xx <= 4 && yy >= 0 && yy <= 4 && !v[xx][yy] && mp[xx][yy] == 0){
now = x;
now.x = xx, now.y = yy;
v[now.x][now.y] = 1;
now.s = x.s + 1;
now.l[x.s] = i;
q.push(now);
}
}
}
return x;
}
int main(){
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
scanf("%d", &mp[i][j]);
}
}
node res = bfs();
printf("(0, 0)\n");
int x = 0 , y = 0;
for(int i = 0; i < res.s; i++){
x += dx[res.l[i]];
y += dy[res.l[i]];
printf("(%d, %d)\n", x, y);
}
return 0;
}
12 .hdu1241 https://vjudge.net/problem/HDU-1241
题解:联通块计数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dx[] = {0, 0, -1, 1, -1, 1, -1, 1};
int dy[] = {-1, 1, 0, 0, -1, 1, 1, -1};
int n, m, cnt;
char mp[105][105];
int v[105][105];
bool check(int x, int y){
if(v[x][y] || x < 0 || x >= n || y < 0 || y >= m || mp[x][y] == '*')
return false;
return true;
}
void dfs(int x, int y){
int xx, yy;
v[x][y] = cnt;
for(int i = 0; i < 8; i++){
xx = x + dx[i], yy = y + dy[i];
if(check(xx, yy))
dfs(xx, yy);
}
}
int main(){
while(scanf("%d%d", &n, &m) == 2){
cnt = 0;
memset(v, 0, sizeof(v));
if(n == 0 && m == 0)
break;
for(int i = 0; i < n; i++){
scanf("%s", mp[i]);
}
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(!v[i][j] && mp[i][j] == '@'){
cnt++;
dfs(i, j);
}
}
}
printf("%d\n", cnt);
}
return 0;
}
13 .hdu1495 https://vjudge.net/problem/HDU-1495
题解:倒水问题,有数学解法(见网上)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int S, N, M;
struct node{
int a, b, c;
int s;
};
bool v[105][105][105];
bool check(node x){
if(x.a == x.b && x.a == S/2 || x.b == x.c && x.c == S/2 || x.a == x.c && x.c == S/2)
return true;
return false;
}
int bfs(){
queue<node> q;
node st;
st.a = S, st.b = st.c = 0;
st.s = 0;
q.push(st);
v[S][0][0] = 1;
while(q.size()){
node now = q.front();
q.pop();
if(check(now)){
return now.s;
}
for(int i = 1; i <= 6; i++){
node nxt;
if(i == 1){//a->b
if(now.a + now.b <= N){
nxt.b = now.a + now.b;
nxt.a = 0;
nxt.c = now.c;
}
else{
nxt.a = now.a + now.b - N;
nxt.b = N;
nxt.c = now.c;
}
}
else if(i == 2){//a->c
if(now.a + now.c <= M){
nxt.c = now.a + now.c;
nxt.a = 0;
nxt.b = now.b;
}
else{
nxt.a = now.a + now.c - M;
nxt.c = M;
nxt.b = now.b;
}
}
else if(i == 3){//b->a
if(now.b + now.a <= S){
nxt.a = now.b + now.a;
nxt.b = 0;
nxt.c = now.c;
}
else{
nxt.b = now.a + now.b - S;
nxt.a = S;
nxt.c = now.c;
}
}
else if(i == 4){//b->c
if(now.b + now.c <= M){
nxt.c = now.b + now.c;
nxt.b = 0;
nxt.a = now.a;
}
else{
nxt.b = now.b + now.c - M;
nxt.c = M;
nxt.a = now.a;
}
}
else if(i == 5){//c->a
if(now.c + now.a <= S){
nxt.a = now.c + now.a;
nxt.c = 0;
nxt.b = now.b;
}
else{
nxt.c = now.a + now.c - S;
nxt.a = S;
nxt.b = now.b;
}
}
else if(i == 6){//c->b
if(now.c + now.b <= N){
nxt.b = now.c + now.b;
nxt.c = 0;
nxt.a = now.a;
}
else{
nxt.c = now.c + now.b - N;
nxt.b = N;
nxt.a = now.a;
}
}
if(!v[nxt.a][nxt.b][nxt.c]){
nxt.s = now.s + 1;
v[nxt.a][nxt.b][nxt.c] = 1;
q.push(nxt);
}
}
}
return -1;
}
int main(){
//freopen("D://Aduipai//data.txt", "r", stdin);
//freopen("D://Aduipai//wa.txt", "w", stdout);
int kase = 0;
while(scanf("%d %d %d", &S, &N, &M) == 3){
memset(v, 0, sizeof(v));
if(!S && !N && !M)
break;
if(S % 2){
printf("NO\n");
continue;;
}
int ans = bfs();
if(ans == -1){
printf("NO\n");
}
else{
printf("%d\n",ans);
}
}
return 0;
}