2024年暑假ACM集训第3场

A:颜色叠加

题目描述

热爱科学的Kimi这段时间在研究各种颜色,今天他打算做一个关于颜色叠加的小实验。
Kimi有很多张蓝色和黄色的长方形透明塑料卡片。众所周知,如果把蓝色和黄色混合在一起就会变成绿色。因此,Kimi对着光观察蓝色透明卡片和黄色透明卡片的叠加部分也就可以看到绿色啦。
假设在一个二维平面中,一张蓝色的透明卡片和一张黄色的透明卡片都与坐标轴平行放置,即卡片的横边与X轴平行,竖边与Y轴平行。
现在给出一张蓝色卡片和一张黄色卡片的左上角坐标(均为整数)以及两张卡片的长和宽(均为正整数)。
【注意:此处定义与X轴平行的那组边为长边,与Y轴平行的那组边为宽边】
请编写一个程序计算这两张卡片叠加后所形成的绿色区域的面积。

输入

单组输入。
第1行输入四个整数,分别表示蓝色长方形透明卡片的左上角坐标(X坐标和Y坐标)、长和宽。两两之间用英文空格隔开。
第2行输入四个整数,分别表示黄色长方形透明卡片的左上角坐标(X坐标和Y坐标)、长和宽。两两之间用英文空格隔开。
两张长方形透明卡片的X坐标和Y坐标的取值范围为[-1000, 1000],长和宽的取值范围为[1,200]。

输出

输出一个非负整数,表示两张卡片叠加后所形成的绿色区域的面积。

样例输入 Copy
0 100 200 100
100 150 75 75
样例输出 Copy
1875
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int a, b, aa, bb, c, d, cc, dd;
    int i, j;
    cin >> a >> b >> c >> d;
    cin >> aa >> bb >> cc >> dd;
    int dx = abs(a - aa);
    int dy = abs(b - bb);
    if (a > aa)
        i = min(c, cc - dx);
    else
        i = min(cc, c - dx);
    if (b < bb)
        j = min(d, dd - dy);
    else
        j = min(dd, d - dy);
    if (i > 0 && j > 0)
        cout << i * j << "\n";
    else
        cout << 0 << "\n";
    return 0;
}

 B:勤劳的老杨

题目描述

勤劳的老杨最近收到了一个任务清单,在这个清单上有N项不同的工作任务。对于每一项任务都给出了两个时间[X, Y],其中X表示任务的起始时间(任务从第X天开始,包含第X天),Y表示任务的结束时间(任务到第Y天结束,包含第Y天)。
认真的老杨对待每一项任务都是一心一意的。一旦他决定做某一项任务,在该任务没有完成之前他不会同时再做另一项任务,也就是说在任意时刻老杨手头最多只有一项任务。
假设完成每一项任务所获得的报酬都是相等的。那么,老杨应该如何来安排自己的时间才可以得到最多的报酬呢?
请你编写一个程序帮老杨计算出他最多可以完成的任务数量。保证至少能完成一项任务。

输入

单组输入。
第1行输入一个正整数N表示任务清单上任务的总数。(N<=1000)
第2行到第N行每一行包含两个正整数,分别表示每一项任务的开始时间和结束时间,两个正整数之间用空格隔开。

输出

输出老杨最多可以完成的任务数量。

样例输入 Copy
7
1 4
1 3
2 7
3 4
4 6
5 10
7 8
样例输出 Copy
3
提示

对于输入样例,最多可以完成的任务数量为3,对应[1, 3](第2项任务),[4, 6](第5项任务)和[7, 8](第7项任务)这三项任务。

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
struct S
{
    int x, y;
} a[1005];
bool cmp(S a, S b)
{
    return a.y < b.y;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i].x >> a[i].y;
    sort(a, a + n, cmp);
    int t = 0;
    int sum = 0;
    for (int i = 0; i < n; i++)
        if (a[i].x > t)
        {
            t = a[i].y;
            sum++;
        }
    cout << sum << "\n";
    return 0;
}

 C:秘密大厦的访客

题目描述

Kimi最近在负责一栋秘密大厦的安保工作,他的工作是记录大厦的来访者情况。
每个来访者都有一个与之对应的唯一编号,在每一条到访记录中记录了该来访者的编号。
现在Kimi需要统计每一条记录中的来访者是第几次光临秘密大厦。

输入

单组输入,每组两行。
第1行包含一个正整数n,表示记录的条数,n不超过1000;
第2行包含n个正整数,依次表示Kimi的记录中每位来访者的编号,两两之间用空格隔开。

输出

输出1行,包含n个正整数,两两之间用空格隔开,依次表示每条记录中的来访者编号是第几次出现。

样例输入 Copy
6
1 1 2 2 3 1
样例输出 Copy
1 2 1 2 1 3
#include<iostream>
using namespace std;
int a[1000];
int main()
{
    int n,s;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>s;
        a[s]++;
        printf("%d ",a[s]);
    }
    return 0;
}

 D:最大素数

题目描述

输入一个数字字符串,从中删除若干个(包含0个)数字后可以得到一个素数,请编写一个程序求解删除部分数字之后能够得到的最大素数。
例如,输入“1234”,删除1和4,可以得到的最大素数为23。

输入

单组输入。
输入一个数字字符串,字符串的长度不超过10。

输出

输出删除0个或者多个数字之后所能得到的最大素数。如果删除到最后也得不到素数则输出“No result.” 。

样例输入 Copy
1234
样例输出 Copy
23
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
bool fun(long long n)
{
    if (n <= 1)
        return false;
    for (int i = 2; i <= sqrt(n); i++)
        if (n % i == 0)
            return false;
    return true;
}
long long check(string s, long long sum)
{
    if (s.size() == 0)
        return sum;
    long long num = stoll(s);
    if (fun(num))
        sum = max(sum, num);
    for (int i = 0; i < s.size(); i++)
    {
        string t = s;
        t.erase(i, 1);
        sum = check(t, sum);
    }
    return sum;
}
int main()
{
    string s;
    cin >> s;
    long long sum = check(s, -1);
    if (sum == -1)
        cout << "No result." << endl;
    else
        cout << sum << endl;
    return 0;
}

F:密钥

题目描述

X星人又截获了Y星人的一段密文。
破解这段密文需要使用一个密钥,而这个密钥存在于一个正整数N中。
聪明的X星人终于找到了获取密钥的方法:这个正整数的最后一位是一个非零数K(K>=2),需要将正整数N切分成K个小的整数,并且要使得这K个较小整数的乘积达到最大。而所得到的最大乘积就是破解密文所需的密钥。
你能否帮X星人编写一段程序来得到密钥呢?

输入

单组输入。输入一个正整数N(N的长度小于等于15),且N的最后一位为K,K>=2。

输出

将N划分为K个整数后的最大乘积。

样例输入 Copy
2342
样例输出 Copy
966
#define _CRT_SECURE_NO_WARNINGS
#define sort so
#define P 3.1415927
#define ll long long
const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
#include<iostream>
#include<cstdio>
using namespace std;
#include<string>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#include<unordered_set>
#include<cctype>
#include<vector>
#include<queue>
#include<map>
#include<unordered_map>
#include<stack>
#include<cmath>
int dx[4] = { 0,1,0,-1 };
int dy[4] = { 1,0,-1,0 };
ll f(string a)
{
    ll n = strtoll(a.c_str(), NULL, 10);
    return n;
}
ll dfs(string a, int k)
{
    if (k == 1)return f(a);
    ll s = 0;
    for (int i = 0; i < a.size() - 1; i++)
    {
        string s1 = a.substr(0, i + 1), s2 = a.substr(i + 1);
        for (int j = 1; j < k; j++)
        {
            if (s1.size() >= j && s2.size() >= k - j)
            {
                ll m = dfs(s1, j) * dfs(s2, k - j);
                s = max(m, s);
            }
        }
    }
    return s;
}
int main()
{
    cin.sync_with_stdio(0);
    cout.sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    string a;
    cin >> a;
    int k = a[a.size() - 1] - '0';
    cout << dfs(a, k);
}

 G:第n个数

题目描述

自从学了素数以后,明明喜欢上了数字2、3和5。当然,如果一个数字里面只出现2、3和5这三个数字,他也一样喜欢,例如222、2355、223355。
现在他希望你能够帮他编写一个程序,快速计算出由2、3、5这三个数字组成的由小到大的第n个数,当然也包括2、3和5。

输入

每组输入数据占1行,每行输入一个正整数n。(n<=1000)

输出

每组输出数据占1行,即满足要求的第n个数。

样例输入 Copy
3
样例输出 Copy
5
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int n;
    queue<long long> a;
    cin >> n;
    a.push(2);
    a.push(3);
    a.push(5);
    for (int i = 1; i < n; i++)
    {
        long long t = a.front();
        a.pop();
        a.push(t * 10 + 2);
        a.push(t * 10 + 3);
        a.push(t * 10 + 5);
    }
    cout << a.front() << "\n";
    return 0;
}

 H:你好中国

题目描述

小明一天突发奇想,随机生成了一个全部由大写字母组成的方阵。他惊奇地发现这个方阵中包含中国的英文单词“CHINA”。
他希望你能够编写一个程序,能够找出一个由大写字母组成的方阵中所有不同的“CHINA”,要“CHINA”求中五个字母要连续出现,方向可以是上、下、左、右中的任意一个。
例如在下面的4*4的方阵中就包含了两个不同的“CHINA”。一个是第1行第1列到第3列的“CHI”,加上第2行第3列的“N”以及第2行第2列的“A”组成的“CHINA”;还有一个是第1行第1列到第3列的“CHI”,加上第2行第3列的“N”以及第3行第3列的“A”。
CHIA
CANT
GRAC
BBDE

输入

单组输入,每个测试样例包含N+1行。
第1行为方阵的大小N(N<=30)。
第2行到第N+1行用于存储由大写字母组成的方阵,每一行包含N个大写字母。

输出

输出方阵中包含的不同的CHINA的个数。如果一个都没有找到,则输出0。

样例输入 Copy
4
CHIA
CANT
GRAC
BBDE
样例输出 Copy
2

 

#include <iostream>
#include <cstring>
using namespace std;
int n;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
char a[35][35];
bool b[35][35];
int sum;
string s = "CHINA";
void dfs(int x, int y, int t)
{
    if (t == 5)
    {
        sum++;
        return;
    }
    for (int i = 0; i < 4; i++)
    {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (xx >= 0 &&xx < n &&yy >= 0 &&yy < n && !b[xx][yy] && a[xx][yy] == s[t])
        {
            b[xx][yy] = true;
            dfs(xx, yy, t + 1);
            b[xx][yy] = false;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> a[i][j];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (a[i][j] == 'C')
            {
                memset(b, 0, sizeof(b));
                b[i][j] = true;
                dfs(i, j, 1);
            }
    cout << sum << "\n";
    return 0;
}

I:王子公主游戏

题目描述

小h最近发现一款游戏,在一个二维的地图中王子在(x1,y1)位置,公主在(x2,y2)位置。地图中有很多障碍物,判断王子是否能够救回公主(走到公主的位置)

输入

多组输入,第一行输入一个整数t,表示数据组数(1<=t<=10)
每组输入,第一行两个数字n和m表示地图的大小
后面n行,每行m个字符表示地图
S表示王子的位置,E表示公主的位置,'.'表示可以通过'#'表示障碍物
(n<=100,m<=100)

输出

对于每组数据判断王子是否能够救回公主,能的话输出YES否则输出NO

样例输入 Copy
2
2 2
.E
S.
2 2
#E
S#
样例输出 Copy
YES
NO 
#include <iostream>
#include <cstring>
using namespace std;
int n, m;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
char a[105][105];
bool b[105][105];
int x1, y1, x2, y2;
bool dfs(int x, int y)
{
    if (x == x2 && y == y2)
        return true;
    b[x][y] = true;
    for (int i = 0; i < 4; i++)
    {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (xx >= 0 && xx < n && yy >= 0 && yy < m && !b[xx][yy] && a[xx][yy] != '#')
            if (dfs(xx, yy))
                return true;
    }
    return false;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                cin >> a[i][j];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
            {
                if (a[i][j] == 'S')
                {
                    x1 = i;
                    y1 = j;
                }
                if (a[i][j] == 'E')
                {
                    x2 = i;
                    y2 = j;
                }
            }
        memset(b, 0, sizeof(b));
        if (dfs(x1, y1))
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}
 

 J:最小计分

题目描述

小明最近在研究一个棋盘游戏,游戏规则如下:
一个n*n的棋盘,每个格子里面填写有1、2、3、4这四个数字中的某一个。
首先在第1行第1列(左上角)放置一个棋子,该棋子可以移动至上、下、左、右四个格子中的某一个,每次移动一格(允许重复移动到某一个格子)。
在移动时需要进行计分。如果初始格子中的数字为X,目标格子中的数字为Y,则本次移动计分为|X-Y|,即两个格子中的数字之差。
现在需要把棋子移动到第N行第N列(右下角),请问能够获得的最小计分为多少?

输入

单组输入。
第1行为N。
接下来N行为一个二维数组,表示棋盘上每一个格子及其对应的数字(正整数)。(N≤100)

输出

输出一个正整数,表示最小计分。

样例输入 Copy
3
1 2 4
1 3 1
1 2 1
样例输出 Copy
2
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
int a[105][105];
bool b[105][105];
int f[105][105];
int sum = 0x3f3f3f3f;
void dfs(int x, int y, int s)
{
    if (x == n && y == n)
    {
        sum = min(sum, s);
        return;
    }
    if (s >= sum || s >= f[x][y])
        return;
    f[x][y] = s;
    b[x][y] = true;
    if (x + 1 <= n && !b[x + 1][y])
        dfs(x + 1, y, s + abs(a[x + 1][y] - a[x][y]));
    if (y + 1 <= n && !b[x][y + 1])
        dfs(x, y + 1, s + abs(a[x][y + 1] - a[x][y]));
    if (x - 1 >= 1 && !b[x - 1][y])
        dfs(x - 1, y, s + abs(a[x - 1][y] - a[x][y]));
    if (y - 1 >= 1 && !b[x][y - 1])
        dfs(x, y - 1, s + abs(a[x][y - 1] - a[x][y]));
    b[x][y] = false;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            cin >> a[i][j];
    memset(f, 0x3f, sizeof(f));
    dfs(1, 1, 0);
    cout << sum << endl;
    return 0;
}

 K:抢占地盘

题目描述

小明最近学会了一种棋,这种棋的玩法和围棋有点类似,最后通过比较黑子和白子所占区域的大小来决定胜负。
在下棋过程中,如果白子或者黑子将对方全部围住,则所围区域中的棋子将更换颜色。
如果用1表示黑子,0表示白子,给出如下实例:
1111
0101
1101
0010
因为第2行第3列的白子(0)和第3行第3列的白子(0)完全被黑子(1)围住,因此需要这两个0将变为1。
结果变为:
1111
0111
1111
0010
为了简化问题的求解,只需要大家找出所有被黑子围住的白子,并将这些白子变为黑子后输出。

输入

单组输入。
第1行为一个正整数n(n<=1000),表示棋盘的大小。
接下来n行输入一个n*n的0/1矩阵,其中0表示白子,1表示黑子。

输出

输出转换之后的0/1矩阵。

样例输入 Copy
4
1111
0101
1101
0010
样例输出 Copy

1111
0111
1111
0010

#include <iostream>
#include <cstring>
using namespace std;
int n;
int a[1005][1005];
bool b[1005][1005];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
void dfs(int x, int y)
{
    b[x][y] = true;
    for (int i = 0; i < 4; i++)
    {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx >= 0 && nx < n && ny >= 0 && ny < n && !b[nx][ny] && a[nx][ny] == 0)
            dfs(nx, ny);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
        {
            char c;
            cin >> c;
            a[i][j] = c - '0';
        }
    memset(b, 0, sizeof(b));
    for (int i = 0; i < n; i++)
    {
        if (!b[i][0] && a[i][0] == 0)
            dfs(i, 0);
        if (!b[i][n - 1] && a[i][n - 1] == 0)
            dfs(i, n - 1);
    }
    for (int j = 1; j < n-1; j++)
    {
        if (!b[0][j] && a[0][j] == 0)
            dfs(0, j);
        if (!b[n - 1][j] && a[n - 1][j] == 0)
            dfs(n - 1, j);
    }
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (!b[i][j])
                a[i][j] = 1;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
            cout << a[i][j];
        cout << endl;
    }
    cout << endl;
    return 0;
}

L:电路维修

题目描述

有一种正方形的电路元件,在它的两组相对顶点中,有一组会用导线连接起来,另一组则不会。有N×M个这样的元件,你想将其排列成N行M列放在电路板上。电路板的左上角连接电源,右下角连接灯泡。试求:至少要旋转多少个正方形元件才能让电源与灯泡连通,若无解则输出NO SOLUTION。

输入

第一行有一个整数T表示T(T<=10)组样例,第二行有两个整数N和M。在接下来的N行中,每行有M个字符。每个字符均为 \或/,表示正方形元件上导线的连接方向。

输出

输出共一行,若有解则输出一个整数,表示至少要旋转多少个正方形元件才能让电源与灯泡连通;若无解则输出NO SOLUTION。

样例输入 Copy
1
3 5
\\/\\
\\///
/\\\\
样例输出 Copy
1
提示
对于40%的数据,1≤N≤10,1≤M≤10。对于所有数据,1≤N,M≤500。
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 5e2+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
int n,m;
char a[N][N];
int b[N][N];
char c[5]="\\/\\/";
int dx[4]={1,-1,-1,1};
int dy[4]={1,1,-1,-1};
int ix[4]={0,-1,-1,0};
int iy[4]={0,0,-1,-1};
void bfs(){
    deque<int> q,qu;
    q.push_back(0);
    qu.push_back(0);
    b[0][0]=0;
    while(!q.empty()){
        int t=q.front();
        int tt=qu.front();
        q.pop_front();
        qu.pop_front();
        for(int i=0;i<4;i++){
            int dnx=t+dx[i];
            int dny=tt+dy[i];
            int inx=t+ix[i];
            int iny=tt+iy[i];
            if(dnx>=0&&dnx<=n&&dny>=0&&dny<=m){
                if(c[i]!=a[inx][iny]){
                    int ttt=b[t][tt]+1;
                    if(ttt<b[dnx][dny]){
                        q.push_back(dnx);
                        qu.push_back(dny);
                        b[dnx][dny]=ttt;    
                    }
                }
                else{
                    int ttt=b[t][tt];
                    if(ttt<b[dnx][dny]){
                        q.push_front(dnx);
                        qu.push_front(dny);
                        b[dnx][dny]=ttt;    
                    }
                }
            }
        }
    }
    cout<<b[n][m]<<endl;
}
void solve(){
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    if((n+m)%2==1){
        cout<<"NO SOLUTION\n";
    }
    else{
        for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++){
                b[i][j]=inf;
            }
        }
        bfs();
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 M:魔板

题目描述

Rubik先生在发明了风靡全球魔方之后,又发明了它的二维版本——魔板。这是一张有8个大小相同的格子的魔板:

 
1234
8765
 

我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列1,2,3,4,5,6,7,8来表示。这是基本状态。

这里提供三种基本操作,分别用大写字母A,B,C来表示(可以通过这些操作改变魔板的状态):

A:交换上下两行;

B:将最右边的一列插入最左边;

C:魔板中央作顺时针旋转。下面是对基本状态进行操作的示范:

A:
8765
1234

B:

4123
5876

C:

1724
8635

对于每种可能的状态,这三种基本操作都可以使用。

你要编程计算用最少的基本操作完成基本状态到特殊状态的转换,输出基本操作序列。

输入
输入仅一行,包括8个整数,用空格分开,表示目标状态。
输出
输出文件的第一行包括一个整数,表示最短操作序列的长度。第二行为在字典序中最早出现的操作序列。
样例输入 Copy
2 6 8 4 5 7 3 1
样例输出 Copy
7
BCABCCB
提示
输入数据中的所有数字均为1到8之间的整数。
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <list>
#include <deque>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N = 5e2+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
bool bb[9][9][9][9][9][9][9][9];
struct S{
    int t,y,u,i,g,h,j,k,s;
    string ss;
};
void solve(){
    int t,y,u,i,g,h,j,k;
    cin>>t>>y>>u>>i>>k>>j>>h>>g;
    queue<S> q;
    q.push({1,2,3,4,8,7,6,5,0,""});
    bb[1][2][3][4][8][7][6][5]=true;
    while(!q.empty()){
        auto z=q.front();
        q.pop();
        if(z.t==t&&z.y==y&&z.u==u&&z.i==i&&z.g==g&&z.h==h&&z.j==j&&z.k==k){
            cout<<z.s<<"\n"<<z.ss<<"\n";
            return;
        }
        if(!bb[z.g][z.h][z.j][z.k][z.t][z.y][z.u][z.i]){
            bb[z.g][z.h][z.j][z.k][z.t][z.y][z.u][z.i]=true;
            q.push({z.g,z.h,z.j,z.k,z.t,z.y,z.u,z.i,z.s+1,z.ss+"A"});
        }
        if(!bb[z.i][z.t][z.y][z.u][z.k][z.g][z.h][z.j]){
            bb[z.i][z.t][z.y][z.u][z.k][z.g][z.h][z.j]=true;
            q.push({z.i,z.t,z.y,z.u,z.k,z.g,z.h,z.j,z.s+1,z.ss+"B"});
        }
        if(!bb[z.t][z.h][z.y][z.i][z.g][z.j][z.u][z.k]){
            bb[z.t][z.h][z.y][z.i][z.g][z.j][z.u][z.k]=true;
            q.push({z.t,z.h,z.y,z.i,z.g,z.j,z.u,z.k,z.s+1,z.ss+"C"});
        }
    }
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    //int T;cin>>T;for(int i=1;i<=T;i++)
    solve();
    return 0;
}

 N:棋盘游戏

题目描述

在一个4×4的棋盘上有8个黑棋和8个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的。移动棋子的规则是交换相邻两个棋子。给出一个初始棋盘和一个最终棋盘,请找出一个最短的移动序列使初始棋盘变为最终棋盘。

输入

前四行,每行4个数字(1或者0),描述了初始棋盘;接着是一个空行;第六到第九行,每行4个数字(1或者0),描述了最终棋盘。

输出
输出文件的第一行是一个整数n,表示最少的移动步数。
样例输入 Copy
1111
0000
1110
0010

1010
0101
1010
0101
样例输出 Copy
4
#pragma GCC optimize(2)
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <unordered_set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
char a[15][15],s[15][15];
int x[15],y[15],xx[15],yy[15];
bool b[15];
int n,m;
int mm=inf;
void dfs(int k,int d){
    if(d>mm){
        return;
    }
    if(k>n){
        mm=d;
        return;
    }
    for(int i=1;i<=m;i++){
        if(!b[i]){
            b[i]=true;
            dfs(k+1,d+fabs(x[i]-xx[k])+fabs(y[i]-yy[k]));
            b[i]=false;
        }
    }
}
void solve(){
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>s[i][j];
        }
    }
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            if(s[i][j]<a[i][j]){
                x[++n]=i;
                y[n]=j;
            }
            if(s[i][j]>a[i][j]){
                xx[++m]=i;
                yy[m]=j;
            }
        }
    }
    dfs(1,0);
    cout<<mm<<"\n";
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

 O:移动玩具

题目描述

在一个4×4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到目标状态。

输入

前四行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具。
接着是一个空行。
接下来四行表示玩具的目标状态,每行4个数字1或0,意义同上。

输出
一个整数,所需要的最少移动次数。
样例输入 Copy
1111
0000
1110
0010

1010
0101
1010
0101
样例输出 Copy
4

 

#pragma GCC optimize(2)
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <algorithm>
#include <cstring>
#include <vector>
#include <stack>
#include <queue>
#include <unordered_set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6+5;
const int M = 1e9+7;
const int inf = 0x3fffffff;
const int P = 13331;
char a[15][15],s[15][15];
int x[15],y[15],xx[15],yy[15];
bool b[15];
int n,m;
int mm=inf;
void dfs(int k,int d){
    if(d>mm){
        return;
    }
    if(k>n){
        mm=d;
        return;
    }
    for(int i=1;i<=m;i++){
        if(!b[i]){
            b[i]=true;
            dfs(k+1,d+fabs(x[i]-xx[k])+fabs(y[i]-yy[k]));
            b[i]=false;
        }
    }
}
void solve(){
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>a[i][j];
        }
    }
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            cin>>s[i][j];
        }
    }
    for(int i=1;i<=4;i++){
        for(int j=1;j<=4;j++){
            if(s[i][j]<a[i][j]){
                x[++n]=i;
                y[n]=j;
            }
            if(s[i][j]>a[i][j]){
                xx[++m]=i;
                yy[m]=j;
            }
        }
    }
    dfs(1,0);
    cout<<mm<<"\n";
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //int t;cin>>t;while(t--)
    solve();
    return 0;
}

P:山峰和山谷

题目描述

给定一个n*n的网格状地图,每个方格(i,j)有一个高度wij。如果两个方格有公共顶点,则它们是相邻的。
定义山峰和山谷如下:

  • 均由地图上的一个连通块组成;
  • 所有方格高度都相同;
  • 周围的方格(即不属于山峰或山谷但与山峰或山谷相邻的格子)高度均大于山谷的高度,或小于山峰的高度。

求地图内山峰和山谷的数量。特别地,如果整个地图方格的高度均相同,则整个地图既是一个山谷,也是一个山峰。

输入

第一行一个整数n(2≤n≤1000),表示地图的大小。
接下来n行每行n个整数表示地图。第i行有n个整数wi1,wi2,…,win(0≤wij≤1 000 000 000),表示地图第i行格子的高度。

输出
输出一行两个整数,分别表示山峰和山谷的数量。
样例输入 Copy
5
8 8 8 7 7
7 7 8 8 7
7 7 7 7 7
7 8 8 7 8
7 8 8 8 8
样例输出 Copy
2 1
#include <iostream>
using namespace std;
int a[1005][1005];
int n;
bool b[1005][1005];
int dx[8] = {0, 1, 0, -1, -1, -1, 1, 1};
int dy[8] = {1, 0, -1, 0, -1, 1, -1, 1};
void dfs(int x, int y, bool &h, bool &l)
{
    b[x][y] = true;
    for (int i = 0; i < 8; i++)
    {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (nx < 0 || nx >= n || ny < 0 || ny >= n)
            continue;
        if (a[nx][ny] != a[x][y])
        {
            if (a[nx][ny] > a[x][y])
                h = true;
            else
                l = true;
        }
        else if (!b[nx][ny])
            dfs(nx, ny, h, l);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> a[i][j];
    int s = 0, sum = 0;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (!b[i][j])
            {
                bool h = false, l = false;
                dfs(i, j, h, l);
                if (!h)
                    s++;
                if (!l)
                    sum++;
            }
    cout << s << ' ' << sum << endl;
    return 0;
}

 

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值