2022寒假集训day6
day6
上午还是做四道题
T1
区域
【上机练习】
1、编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线
中水平线和垂直线交点的数目。如下图所示,在 10*10 的二维数组中,有“*”围住了 15
个点,因此面积为 15。
【样例输入】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; }
很正经的搜索回溯啦,
对家庭数和人数进行初始化,如果发现输入中重复出现的元素,说明二者可以算到一起(也就是合为一家)
计数也就减少一个,人数++。