2022寒假集训day6

day6

上午还是做四道题

T1

区域
【上机练习】
1、编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线
中水平线和垂直线交点的数目。如下图所示,在 10*10 的二维数组中,有“*”围住了 15
个点,因此面积为 15。
2022寒假集训day6

【样例输入】area.in
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 1 0 0 1 0
0 0 1 0 0 0 1 0 1 0
0 1 0 1 0 1 0 0 1 0
0 1 0 0 1 1 0 1 1 0
0 0 1 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0
【样例输出】area.out
15

#include <bits/stdc++.h>
using namespace std;
int a[12][12];
int main()
{
    int sum=0;
    for(int i=0;i<12;i++)
        for(int j=0;j<12;j++)
            a[i][j]=0;
    for(int i=0;i<12;i++)
    {
            a[i][0]=-1;
            a[0][i]=-1;
            a[i][11]=-1;
            a[11][i]=-1;
    }
    for(int i=1;i<11;i++)
        for(int j=1;j<11;j++)
        {
            cin>>a[i][j];
        }
     
    for(int i=1;i<11;i++)
        for(int j=1;j<11;j++)
        {
            if(a[i][j]==0&&a[i-1][j]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i][j-1]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i+1][j]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i][j+1]==-1)
                a[i][j]=-1;               
        }
    for(int j=1;j<11;j++)
        for(int i=1;i<11;i++)
        {
            if(a[i][j]==0&&a[i-1][j]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i][j-1]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i+1][j]==-1)
                a[i][j]=-1;
            if(a[i][j]==0&&a[i][j+1]==-1)
                a[i][j]=-1;               
        }   
    for(int i=1;i<11;i++)
        for(int j=1;j<11;j++)
        {
            if(a[i][j]==0)
            sum++;
        }
    cout<<sum;        
}

 整道题给人一种看的很明白,但是没有思路写;

关键在我这道题没用搜索还做了出来(doge

————————————————————————————————————————

T2

奇怪的电梯 洛谷P1135

2、奇怪的电梯(lift)
【问题描述】
大楼的每一层楼都可以停电梯,而且第 i 层楼(1<=i<=N)上有一个数字 Ki(0<=Ki<=N)。
电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果
不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5 代表了 Ki(K1=3,K2=3,......),从一
楼开始。在一楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有-2 楼。那么,
从 A 楼到 B 楼至少要按几次按钮呢?
【输入格式】
输入文件共有二行,第一行为三个用空格隔开的正整数,表示 N,A,B(1≤N≤200, 1 ≤
A,B≤N),第二行为 N 个用空格隔开的正整数,表示 Ki。
【输出格式】
输出文件仅一行,即最少按键次数,若无法到达,则输出-1

 

#include<bits/stdc++.h>
using namespace std;

int n,A,B,cnt=10001;
int k[210];
bool b[210]={0}; 
int d[2]={1,-1};

void dfs(int x,int s)
{
    if(x==B) cnt=min(s,cnt); 
    if(s>cnt) return;
     
    for(int i=0;i<2;i++){
        int X=x+d[i]*k[x];
        if(X>=1 && X<= n && b[X]){
            s++;
            b[x]=false;
                        dfs(X,s);
            b[x]=true;
            s--;
        }
     }      
}

int main(){
    cin>>n>>A>>B;
    
    memset(b,true,sizeof(b));
    for(int i=1;i<=n;i++) cin>>k[i];
    
    b[A]=false;
    if(A==B) cnt=0;
    else dfs(A,0);
    if(cnt==10001) cout<<-1;
    else cout<<cnt;
    return 0;
} 

反复提交了好几次才发现少了memset(b,true,sizeof(b));
一直二十分。整体来说还是标准的深搜。

————————————————————————————————————————

T3

产生数    洛谷P1037

题目描述

给出一个整数 nnn(n<1030n \lt 10^{30}n<1030)和 kkk 个变换规则(k≤15k \le 15k≤15)。

规则:

  • 一位数可变换成另一个一位数。
  • 规则的右部不能为零。

例如:n=234n=234n=234。有规则(k=2k=2k=2):

  • 222->555
  • 333->666

上面的整数 234234234 经过变换后可能产生出的整数为(包括原数):

  • 234234234
  • 534534534
  • 264264264
  • 564564564

共 444 种不同的产生数。

现在给出一个整数 nnn 和 kkk 个规则。求出经过任意次的变换(000次或多次),能产生出多少个不同整数。

仅要求输出个数。

输入格式

第一行两个整数 n,kn,kn,k。

接下来 kkk 行,每行两个整数 xi,yix_i,y_ixi​,yi​。

输出格式

输出能生成的数字个数。

 

#include<iostream>
using namespace std;
string n;
int k,can[10][10];
int ans[500]={1};
int l=1,b[10];

void dfs(int x)
{
    for(int i=0;i<l;i++)
        ans[i]*=x;
    for(int i=0;i<l;i++)
        if(ans[i]>=10)
        {
            ans[i+1]+=ans[i]/10;
            ans[i]%=10;
        }
    while(ans[l]>0)
    {
        ans[l+1]=ans[l]/10;
        ans[l]=ans[l]%10;
        l++;
    }
}
int main()
{
    cin>>n>>k;
    int x,y;
    while(k--)
    {
        cin>>x>>y;
        can[x][y]=1;
    }
    for(int v=0;v<10;v++)
        for(int j=0;j<10;j++)
            for(int i=0; i<10; i++)
                if(i!=j&&j!=v&&i!=v)
                    if(can[i][v]==1&&can[v][j]==1) can[i][j]=1;
    
    int len=n.length();
    for(int i=0; i<len; i++)
    {
        int n1=n[i]-'0',change=1;
        for(int j=0;j<10;j++)
        if(can[n1][j]==1&&n1!=j)
            change++;
        b[n1]=change;
    }
    for(int i=0;i<len;i++) dfs(b[n[i]-'0']);
    for(int i=l-1;i>=0;i--) cout<<ans[i];
    return 0;
}

颇为麻烦的一道题

第一眼上去以为会有规律,结果自己找了几个数据自己算,发现竟然是递推(bushi)。就写个提交,洛谷给我20分,竟然骗到了。

言归正传,首先搜索规则中可以变换的情况,还要用10来取模,如果发现得出的数与之前的相同,不能sum++了

————————————————————————————————————————

T4

家庭问题

【问题描述】
有 n 个人,编号为 1,2,......n,另外还知道存在 K 个关系。一个关系的表达为二元组(α,
β)形式,表示α,β为同一家庭的成员。
当 n,k 和 k 个关系给出之后,求出其*有多少个家庭、最大的家庭中有多少人?
例如:n=6,k=3,三个关系为(1,2),(1,3),(4,5)
此时,6 个人组成三个家庭,即:{1,2,3}为一个家庭,{4,5}为一个家庭,{6}单独为
一个家庭,第一个家庭的人数为最多。

【输入格式】
文件的第一行为 n,k 二个整数(1≤n≤100)(用空格分隔)
接下来的 k 行,每行二个整数(用空格分隔)表示关系
【输出格式】
二个整数(分别表示家庭个数和最大家庭人数)

 

#include <bits/stdc++.h>
using namespace std;
int n,k;
int a,b;
int p[120],sum[120];
int search(int x){
    if(p[x]!=x) p[x]=search(p[x]);
    return p[x];
}
int main(){
    cin>>n>>k;
    int family=n;
    int number=1;
    for(int i=1;i<=n;i++){
        p[i]=1;
        p[i]++;
        sum[i]=1;
    }
    while(k--){
        cin>>a>>b;
        a=search(a),b=search(b);
        if(a!=b){
            p[a]=b;
            sum[b]+=sum[a];
            family--;
            number=max(number,sum[b]);
        } 
            
    }
    cout<<family<<" "<<number;
    return 0;
}

很正经的搜索回溯啦,

对家庭数和人数进行初始化,如果发现输入中重复出现的元素,说明二者可以算到一起(也就是合为一家)

计数也就减少一个,人数++。

 

上一篇:js 防抖 原理


下一篇:从nacos客户端的TIME_WAIT说起