郑州大学“战役杯”第三次比赛题解

1 疫情防控网格化

由于防控形势严峻,现在z市已经开始了全区域的网格化封控管理。该市的区域可以看成一个矩形,其中所有主干道都是水平或垂直的,并且贯穿整个区域。如图所示,黑色表示城区的边界,红色表示城区的主干道,其中边界和主干道宽度都为1,且不存在边界与主干道、主干道与主干道相邻的情况

为了方便网格化管理,我们定义网格单元是由城区边界或主干道围成的区域,且任意网格单元内不能包含主干道。上图中,该城区共被分割成了16个网格单元。

现在给出该区域的地图,需要你统计出该城区划分出了多少个网格单元,以方便安排医务人员和应急物资。

在计算机中,图像的本质就是二维的矩阵。为了方便处理,我们将上述图像中城区边界及里面的内容转化为了二维字符矩阵,详细见输入格式描述。

输入格式:

第一行输入两个整数n,m(3≤n,m≤100)
其后n行,每行m个字符,字符有'*'和'#'两种。'*'代表城区边界或主干道,'#'代表网格单元内区域。

输出格式:

输出一行一个整数,代表地图中的网格单元个数。

输入样例:

3 7
*******
*##*##*
*******

输出样例:

2

源代码

传染:即为当某个元素为#时,其相邻的#的位置均被打上标记,即对于连着的#只计算一个解 

#include <iostream>
using namespace std;
const int N = 1000+10;
char g[N][N];//存图
int a[N][N]={0};//标记数组
int main()
{
    int ans=0;
    int n,m;
    cin>>n>>m;
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            cin>>g[i][j];
        }
    }
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            if(g[i][j]=='#')//如果查到元素为#
            {
                if(a[i+1][j]==0&&a[i-1][j]==0&&a[i][j+1]==0&&a[i][j-1]==0)//且该元素周围无标记
                {
                    a[i][j]=1;//标记该位置
                    ans++;//答案加一
                }
                else a[i][j]=1;//若周围有标记则“传染”
            }
        }
    }
    cout<<ans;
    return 0;
}

 2 子区域计数

由于防控形势严峻,现在z市已经开始了全区域的网格化封控管理。该市的区域可以看成一个矩形,其中所有主干道都是水平或垂直的,并且贯穿整个区域。如图所示,黑色表示城区的边界,红色表示城区的主干道。其中边界和主干道宽度都为1,且不存在边界与主干道、主干道与主干道相邻的情况。

为了方便网格化管理,我们定义网格单元是由城区边界或主干道围成的区域,且任意网格单元内不能包含主干道。上图中,该城区共被分割成了16个网格单元。

同时,网格化管理的本质思想是“分治”,不同的划分粒度对于管理效率会产生深远的影响。所以,这次W同学思考的不仅仅是网格单元,而是子网格。

子网格的定义为:子网格也是一个矩形,且子网格矩形4个角的对应点都位于边界与边界、边界与主干道、主干道与主干道的交点上。我们认为两个子网格是相同的,当且仅当两个子网格的4个角对应点全部重合。根据这个定义,我们可以知道,任意的网格单元也是一种子网格,整个城区的矩形也是一种特殊的子网格。

同样给出上述的图像,你能否帮小W计算下,有多少种可能的子网格?

输入格式:

第一行输入两个整数n,m(3≤n,m≤100)
其后n行,每行m个字符,字符有'*'和'#'两种。'*'代表城区边界或主干道,'#'代表网格单元内区域。

输出格式:

输出一行一个整数,代表符合条件不同子网格的个数。

输入样例:

3 7
*******
*##*##*
*******

 源代码

 

 标记数组处理以后对应关系

#include <iostream>
using namespace std;
const int N = 1000+10;
char g[N][N];//存图 
int a[N][N]={0};//标记数组 
int ans=0;
int n,m;
int main()
{
    cin>>n>>m;
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            cin>>g[i][j];//对图进行输入时 
            if(g[i][j]=='#')//若此元素为# 
            {
				for(int k = 0;k < n;k ++ )a[k][j]=1;//该元素所在行打标记 
				for(int l = 0;l < m;l ++ )a[i][l]=1;//该元素所在列打标记 
			}
        }
    }
    //开始查为*且未被标记的 
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            if(a[i][j]==0&&g[i][j]=='*')
            {
				for(int k = i;k < n;k ++ )
				{
					for(int l = j;l < m;l ++ )
					{
						if(k!=i&&l!=j&&g[k][l]=='*'&&a[k][l]==0)ans++;
						//如果查到的*不同行不同列且未被标记则为一个矩形的解 
					}
				}
			}
        }
    }
    cout<<ans;
    return 0;
}

 3 怀旧的思考挑战

疫情来了,柴刘青山在寝室关着非常无聊,和室友一起玩跑跑卡丁车这款老游戏。

这款游戏有一个模式叫做组队竞速,每局8个人,分为两队,最终比拼哪队总分更高。

第一名冲线得到8分,第二名得到7分,以此类推,第八名得到1分。

柴刘青山好奇自己队伍在某一局游戏中是否能得到某个总分,如果可以,有多少种排名情况可以达成该总分?

后记:柴刘青山和室友们寻求过短暂的放松后,决定还是在学业上开启“竞速模式”,约定共同努力学习,参加“战疫杯”!

输入格式:

第一行一个正整数n,表示猜想的n总分。 0≤n≤10000

输出格式:

如果可以达成,输出一个正整数x,代表有多少种排名情况。
如果不能达成,输出NO。

输入样例:

25

输出样例:

1

样例解释1

柴刘青山的队伍需要取得1、2、3、5名,对应8+7+6+4=25。有且仅有这一种情况。

源代码 

从高到低枚举即可,注意在枚举的时候我们是要尽量满足那个解的情况,因此我们要从大到小进行枚举,且枚举的时候每个内层变量是外层变量的后一位,因此我们可以避免对于枚举的四个数进行判断是否两两,节省大量程序运算时间的同时也能够保证四个数各不相同

#include <iostream>
using namespace std;
int main()
{
    int num;
    cin>>num;
    int ans=0;
    for(int i = 8;i >= 1;i -- )
    {
        for(int j = i-1;j >= 1;j -- )
        {
            for(int k = j-1;k >= 1;k -- )
            {
                for(int l = k-1;l >= 1;l -- )
                {
                    if(i+j+k+l==num)ans++;
                }
            }
        }
    }
    if(ans==0)cout<<"NO";
    else cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/couchpotatoshy/article/details/124718015