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;
}
下面附上别人大佬过的ac代码(膜拜)
点击查看代码
//代码来源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;
}
posted @ 2022-03-14 22:10  真⸙的菜狗꧔ꦿ  阅读(98)  评论(0)    收藏  举报