poj刷题记录
刷题记录
以前码许多题都没留下什么,这次打算弄个记录本菜狗博客
之后会不定期更新
一.基本算法
1.枚举
1753题
题目链接
题目大意:
给一个4*4的矩阵,输入w或者b,其中w代表白色,b代表黑色,每回合可以在矩阵中随便选3到5个进行翻转(包括自己,上面,下面,左边,右边(如果有的话)),求把这矩阵中的全翻转成一种颜色,如果开始就是的话输出0,不可能的话输出Impossible,可以的话输出翻转的回合数
应该就是这个意思吧,本菜狗英语也不好的说QAQ
下面是ac代码的说
点击查看代码
//乍一看,应该是弱化版的熄灯问题吧(不了解熄灯问题的可以直接网上搜索)
//这里打算用易懂的数组来做,毕竟我二进制运算也不熟练QAQ
//菜狗博客https://www.cnblogs.com/zhendecaigou
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
int st[6][6];//初始状态
int ed[6][6];//记录翻转后的情况
int press[6][6];//记录翻转次数
void init()//进行初始化
{
memset(press,0,sizeof(press));
memcpy(ed,st,sizeof(ed));
}
int panduan()//进行判断最后是否全一样的颜色
{
int num=0;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
num+=ed[i][j];
return num;
}
int jieguo()//记录翻转的次数
{
int num=0;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
num+=press[i][j];
return num;
}
void fanzhuan(int a,int b)//对周围点进行翻转
{
ed[a][b]=!ed[a][b];
ed[a+1][b]=!ed[a+1][b];
ed[a][b+1]=!ed[a][b+1];
ed[a-1][b]=!ed[a-1][b];
ed[a][b-1]=!ed[a][b-1];
press[a][b]=1;
}
int main()
{
int num=0;//记录开始是全白或者全黑
char str;
memset(st,0,sizeof(st));
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{cin>>str;
if(str=='w')
num++,st[i][j]=1;}
if(num==0||num==16)
{
cout<<0;
return 0;
}
int ans1=1<<30,ans2=1<<30;//记录翻转的次数
int fan[5];//记录循环翻转情况
for(int i=0;i<pow(2,4);i++)//进行循环,不了解的可以去看看熄灯问题
{
init();
fan[0]=i&1;//这里反正数据小,偷懒下没问题吧,嘿嘿
fan[1]=i&2;
fan[2]=i&4;
fan[3]=i&8;
for(int i=0;i<4;i++)
if(fan[i])
fanzhuan(1,i+1);
for(int ii=2;ii<=4;ii++)
for(int jj=1;jj<=4;jj++)
{
if(ed[ii-1][jj]==0)//这里考虑打算全弄白
fanzhuan(ii,jj);
}
if(panduan()==16)//完成了
{
ans1=min(jieguo(),ans1);//求最小值
}
}
//copy
for(int i=0;i<pow(2,4);i++)//进行循环,不了解的可以去看看熄灯问题
{
init();
fan[0]=i&1;//这里反正数据小,偷懒下没问题吧,嘿嘿
fan[1]=i&2;
fan[2]=i&4;
fan[3]=i&8;
for(int i=0;i<4;i++)
if(fan[i])
fanzhuan(1,i+1);
for(int ii=2;ii<=4;ii++)
for(int jj=1;jj<=4;jj++)
{
if(ed[ii-1][jj]==1)//这里考虑打算全弄黑
fanzhuan(ii,jj);
}
if(panduan()==0)//完成了
{
ans2=min(jieguo(),ans2);//求最小值
}
}
if(ans1==1<<30&&ans2==1<<30)//如果ans什么的没交换的话
cout<<"Impossible";
else
cout<<min(ans1,ans2);//输出结果更小的那个
return 0;
}
2965题
题目链接
题目意思:
给定4*4的矩阵,有-号和+号,每次选中一个进行改变的话的话行和列的也会改变(+号变-,反之-号变+),求最少要多少次能将符号全变-
emm
这题我直接暴力写的(不过暴力好像也有过的,我没剪枝)(话说也可以用深搜来写,感兴趣的可以去查下),结果超时(已摆烂),我就放一下我这写的这种垃圾代码吧,让它作为我曾经码过的证明,虽然还是错了的说QAQ
点击查看代码
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
int st[5][5];
int ed[5][5];
int press[5][5];
int paixu[20];
void anya(int a,int b)
{
for(int i=0;i<4;i++)
ed[a][i]=!ed[a][i],ed[i][b]=!ed[i][b];
ed[a][b]=!ed[a][b];
press[a][b]=1;
}
void init()
{
memset(paixu,0,sizeof(paixu));
memset(press,0,sizeof(press));
memcpy(ed,st,sizeof(ed));
}
bool panduan()
{
int num=0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
num+=ed[i][j];
}
if(num==16)
return true;
else
return false;
}
void prin()
{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
if(press[i][j])
cout<<i+1<<" "<<j+1<<endl;
}
}
int thenum()
{
int num=0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
num+=press[i][j];
}
return num;
}
int main()
{
char str;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
cin>>str;
if(str=='-')
st[i][j]=1;
else
st[i][j]=0;
}
int ans=1<<30;
int num=-1;
for(int i=0;i<pow(2,16);i++)
{
init();
int temp=i;
int j;
for(j=0;temp;j++)
paixu[j]=temp&1,temp>>=1;
for(int k=0;k<=j;k++)
{
if(paixu[k])
anya(k/4,k%4);
}
if(panduan())
{
int temp2=ans;
ans=min(ans,thenum());
if(ans<temp2)
num=i;
}
}
cout<<ans<<endl;
init();
int temp=num;
int j;
for(j=0;temp;j++)
paixu[j]=temp&1,temp/=2;
for(int k=0;k<=j;k++)
{
if(paixu[k])
anya(k/4,k%4);
}
prin();
return 0;
}
点击查看代码
//代码来源http://poj.org/showmessage?message_id=156561
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
bool mark[4][4];
char s[4][4];
int main()
{
int i,j,k;
int ci[16],cj[16];
int nas = 0;
memset(mark,0,sizeof(mark));
for(i = 0;i < 4;i++)
cin >> s[i];
for(i = 0;i < 4;i++)
for(j = 0;j < 4;j++)
{
char c = s[i][j];
if(c == '+')
{
mark[i][j] = !mark[i][j];
for(k = 0;k < 4;k++)
{
mark[i][k] = !mark[i][k];
mark[k][j] = !mark[k][j];
}
}
}
for(i = 0;i < 4;i++)
for(j = 0;j < 4;j++)
if(mark[i][j] == true)
{
ci[nas] = i + 1;
cj[nas] = j + 1;
nas ++;
}
printf("%d\n",nas);
for(i = 0;i < nas;i++)
{
printf("%d %d\n",ci[i],cj[i]);
}
return 0;
}
四.简单搜索
由于个人原因,想先刷深搜什么的,前面的以后再写
1.深度优先搜索
2488题
题目链接
题目大意,给定n代表n种样例,后面输入pq,代表棋盘长宽,骑士可以任意位置出发(其实就是A1开始的说),骑士走的方向为日字(我刚开始还不知道QAQ),要求把棋盘所有位置走一遍,如果不可以输出impossible,如果可以,按以"lexicographically"方式(可以看看这个)输出(这时候我又是一脸懵逼的QAQ,我不愧是菜狗)具体看上面链接的题目吧
下面附上我ac的代码(感觉还有很多地方需要加强)
点击查看代码
#include<iostream>
#include<cstring>
#include<string>
#include<stack>
using namespace std;
typedef pair<int,int> PLL;
struct k{
int prex,prey;
}weizhi[100][100];
int w[100][100];
int n,p,q,num=1;
int ansx,ansy;
int dir[8][2]={-1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2};//顺序不能错,否则wa(别问我怎么知道的QAQ)
bool check1()
{
for(int i=0;i<p;i++)
for(int j=0;j<q;j++)
if(!w[i][j])return false;
return true;
}
bool check2(int x,int y)
{
if(x>=p||x<0||y>=q||y<0||w[x][y])
return false;
return true;
}
bool dfs(int xx,int yy)
{
if(check1())
return true;
for(int i=0;i<8;i++)
{
int xx2=xx+dir[i][0];
int yy2=yy+dir[i][1];
if(!check2(xx2,yy2))
continue;
weizhi[xx2][yy2].prex=xx;
weizhi[xx2][yy2].prey=yy;
w[xx2][yy2]=true;
ansx=xx2,ansy=yy2;
if(dfs(xx2,yy2))
return true;
w[xx2][yy2]=false;
}
return false;
}
void putans(int num)//其实这里写的不太好
{
cout<<"Scenario #"<<num<<":"<<endl;
stack<PLL>ans;
int xq=ansx,yq=ansy;
while((xq+yq)!=-2)
{
ans.push({xq,yq});
int num1,num2;
num1=weizhi[xq][yq].prex;
num2=weizhi[xq][yq].prey;
xq=num1,yq=num2;
}
int nums=ans.size();
for(int i=0;i<nums;i++)
{
char qq=ans.top().second+'A';
cout<<qq<<ans.top().first+1;
ans.pop();
}
cout<<endl<<endl;
}
int main()
{
cin>>n;
while(n--)
{
memset(weizhi,0,sizeof weizhi);
memset(w,0,sizeof w);
weizhi[0][0].prex=-1,weizhi[0][0].prey=-1;
w[0][0]=true;
cin>>p>>q;
if(p==1&&q==1)
{
cout<<"Scenario #"<<num<<":"<<endl;
cout<<"A1"<<endl<<endl;
num++;
continue;
}
if(dfs(0,0))
putans(num),num++;
else
{
cout<<"Scenario #"<<num<<":"<<endl;
cout<<"impossible"<<endl<<endl;
num++;
}
}
return 0;
}
3083题
题目链接
题目意思,找按左优先和按右优先(这2都是dfs)和最短路径(这bfs)
题目思路的话可以参考下这个网站
哎,这题我菜狗也不愧是菜狗,还是直接看看别人大佬优质ac的代码吧
点击查看代码
//代码来源:http://poj.org/showmessage?message_id=355265
#include <cstdio>
using namespace std;
const int d[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}, t[] = {1, 0, -1, 2};
int T, n, m, sx, sy;
char mp[45][45];
bool vis[45][45];
struct ff
{
int x, y, s;
} que[1605];
bool check(int x, int y) { return (1 <= x && x <= n && 1 <= y && y <= m && mp[x][y] != '#'); }
int DFS(int x, int y, int flg, int s, int p)
{
if (mp[x][y] == 'E')
return s;
int f, x_, y_;
for (int i = 0; i < 4; i++)
{
f = (flg + t[i] * p + 4) % 4;
x_ = x + d[f][0], y_ = y + d[f][1];
if (check(x_, y_))
return DFS(x_, y_, f, s + 1, p);
}
}
int BFS()
{
int hed = 0, tal = 1, x_, y_;
vis[sx][sy] = 1, que[1].x = sx, que[1].y = sy, que[1].s = 1;
while (hed != tal)
{
++hed;
for (int i = 0; i < 4; i++)
{
x_ = que[hed].x + d[i][0], y_ = que[hed].y + d[i][1];
if (check(x_, y_) && !vis[x_][y_])
{
vis[x_][y_] = 1, que[++tal].s = que[hed].s + 1, que[tal].x = x_, que[tal].y = y_;
if (mp[x_][y_] == 'E')
return que[tal].s;
}
}
}
}
int main()
{
scanf("%d", &T);
while (T--)
{
scanf("%d%d%*c", &m, &n);
for (int i = 1; i <= n; i++, getchar())
for (int j = 1; j <= m; j++)
{
mp[i][j] = getchar(), vis[i][j] = 0;
if (mp[i][j] == 'S')
sx = i, sy = j;
}
printf("%d %d %d\n", DFS(sx, sy, 0, 1, -1), DFS(sx, sy, 0, 1, 1), BFS());
}
return 0;
}
3009题
题目链接
题目意思:输入w行h列,输入包括0123这4种数字,直到00结束,其中2为搜索开始点,3为结束点,1为障碍物,0为空,在是点2的位置开始移动(上下左右),如果不是0或者2的话不能移动,在移动种的时候到边界外失败,到1前的话停止,且1变成0,到3的话成功,每上下左右移动一次(直到停下)算一次,求成功的最小次数(本菜狗的语言表达能力还有待提高QAQ)
思路:dfs暴力
emm,下面是本菜狗敲的ac代码
点击查看代码
//该代码借鉴了该网站的代码
//https://www.cnblogs.com/Ash-ly/p/5728439.html
//orz
#include <iostream>
#include <cstring>
using namespace std;
int a[25][25];
int w, h;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int stx, sty;
int ans;
int judge(int x, int y)
{
if (a[x][y] == -1)
return 1;
else if (a[x][y] == 2 || a[x][y] == 0)
return 2;
else if (a[x][y] == 1)
return 3;
else
return 4;
}
void dfs(int x, int y, int dep)
{
if (dep > 10)
return;
else
{
for (int i = 0; i < 4; i++)
{
int xx = x, yy = y;
x += dir[i][0];
y += dir[i][1];
if (judge(x, y) == 1)
{
x = xx;
y = yy;
continue;
}
else if (judge(x, y) == 2)
{
while (judge(x, y) == 2)
x += dir[i][0], y += dir[i][1];
if (judge(x, y) == 1)
{
x = xx;
y = yy;
continue;
}
if (judge(x, y) == 4)
{
if ((dep + 1) < ans)
ans = dep + 1;
return;
}
if (judge(x, y) == 3)
{
a[x][y] = 0;
dfs(x - dir[i][0], y - dir[i][1], dep + 1);
a[x][y] = 1;
x = xx;
y = yy;
}
}
else if (judge(x, y) == 3)
{
x = xx;
y = yy;
continue;
}
else if (judge(x, y) == 4)
{
if ((dep + 1) < ans)
ans = dep + 1;
return;
}
}
}
}
int main()
{
while (cin >> w >> h, w || h)
{
ans = 1 << 30;
memset(a, -1, sizeof a);
for (int i = 1; i <= h; i++)
for (int j = 1; j <= w; j++)
{
cin >> a[i][j];
if (a[i][j] == 2)
stx = i, sty = j;
}
dfs(stx, sty, 0);
if (ans > 10)
cout << -1 << endl;
else
cout << ans << endl;
}
return 0;
}
1321题
题目链接
意思的话直接看题
下面就直接放ac代码吧
点击查看代码
#include <iostream>
#include <cstring>
using namespace std;
int ans;
int n, h, k;
char map[10][10];
int p[10];
void dfs(int x)
{
if (h == k)
{
ans++;
return;
}
if (n == x)
return;
for (int i = 0; i < n; i++)
if (map[x][i] == '#' && !p[i])
{
p[i] = 1;
k++;
dfs(x + 1);
p[i] = 0;
k--;
}
dfs(x + 1);
}
int main()
{
while (cin >> n >> h, (n + 1) || (h + 1))
{
ans = k = 0;
memset(map, 0, sizeof map);
memset(p, 0, sizeof p);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> map[i][j];
dfs(0);
cout << ans << endl;
}
return 0;
}
2251题
题目链接
题目大意:三维迷宫问题,输入3个数,代表迷宫高长宽,当都是0时结束,s为开始点,e为结束点,.代表可走#代表墙,能走的话按照样例输出花了多少时间(每一步1分钟),不能的话输出Trapped!
思路:简单的迷宫问题,就是多了一个z而已
这里本菜狗用的是广搜
下面附上ac代码
点击查看代码
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
char map[35][35][35];
int tim[35][35][35];
int l,r,c;
int ans;
int stx,sty,stz;
int dir[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
typedef struct k
{
int xx,yy,zz;
}node;
int main()
{
while(cin>>l>>r>>c,l||r||c)
{
queue<node>q;
ans=0;
memset(tim,0,sizeof tim);
for(int i=0;i<l;i++)
for(int j=0;j<r;j++)
for(int k=0;k<c;k++)
{cin>>map[i][j][k];
if(map[i][j][k]=='S')
stz=i,sty=j,stx=k,map[i][j][k]='#';}
node a={stx,sty,stz};
q.push(a);
while(!q.empty())
{
int x1=q.front().xx;
int y1=q.front().yy;
int z1=q.front().zz;
q.pop();
if(ans)
break;
else
for(int i=0;i<6;i++)
{
int x2=x1+dir[i][0];
int y2=y1+dir[i][1];
int z2=z1+dir[i][2];
if(x2<0||x2>=c||y2<0||y2>=r||z2<0||z2>=l||map[z2][y2][x2]=='#')
continue;
else
{
node h={x2,y2,z2};
tim[z2][y2][x2]=tim[z1][y1][x1]+1;
if(map[z2][y2][x2]=='E')
{
ans=tim[z2][y2][x2];
break;
}
map[z2][y2][x2]='#';
q.push(h);
}
}
}
if(ans==0)
cout<<"Trapped!"<<endl;
else
cout<<"Escaped in "<<ans<<" minute(s)."<<endl;
}
return 0;
}
2.广度优先搜索
3278题
题目链接
题目意思:
给定2个数,第一个数到第二个数走的方式有向前或者向后一格,或者向前2倍,求到第二个数最小次数
题目不难,简单的广搜(当然也可以动态规划来写)
下面直接放本菜狗过的ac代码吧
点击查看代码
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int ti[200005];
int a, b;
int main()
{
cin >> a >> b;
memset(ti, 0, sizeof ti);
queue<int> q;
q.push(a);
if(a>b)
ti[b]=a-b;
else if(a==b)
{
cout<<0;//本菜狗一直wa,后来才发觉是忘了这个QAQ
return 0;
}
while (!q.empty())
{
if (ti[b] != 0)
break;
int k = q.front();
q.pop();
if ((k - 1) >= 0 && !ti[k - 1])
q.push(k - 1), ti[k - 1] = ti[k] + 1;
if ((k + 1) <= 100005 && !ti[k + 1])
q.push(k + 1), ti[k + 1] = ti[k] + 1;
if ((k * 2 <= 100005) && !ti[2 * k])
q.push(2 * k), ti[k * 2] = ti[k] + 1;
}
cout << ti[b];
return 0;
}
1426题
题目链接
题目意思,输入数(直到0结束),求这个数的其中一个倍数为0和1组成的数
emm,感觉这题不够严谨
我直接放ac代码吧
点击查看代码
//给大家看个笑话,这下面这代码能过!
//是数据给得太离谱了吧?。。。
/*
#include<iostream>
using namespace std;
int main()
{
int n;
while(cin>>n,n)
cout<<n<<endl;
}
*/
//题目说了The decimal representation of m must not contain more than 100 digits
//那么按道理应该用字符串做啊
//but
//数据给小了,200个实际上最多也不超过long long
//可以参考下如下网站,把1到200的数都枚举了出来orz
//http://poj.org/showmessage?message_id=355107
//下面就敲一个用long long 的bfs吧(虽然说也不是很严谨)
#include<iostream>
#include<queue>
using namespace std;
#define int long long
int n,ans;
signed main()
{
while(cin>>n,n)
{
ans=0;
queue<int>q;
q.push(1);
while(!q.empty())
{
int num=q.front();
q.pop();
if(num%n==0)
{
ans=num;
break;
}
else
{
q.push(num*10+1);
q.push(num*10);
}
}
cout<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号