1.27 模拟赛

1.队列

编程计算由“*”号围成的下列图形的面积。面积计算方法是统计*号所围成的闭合曲线
中水平线和垂直线交点的数目。

这道题很水,甚至可以不用搜索,直接循环两次就行

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48 ; ch=getchar();}
	return x*f;
}
int a[20][20];
int ans;
int main(){
	for(register int i(1) ; i<=10 ; i=-~i){
		for(register int j(1) ; j<=10 ; j=-~j){
			cin >> a[i][j];
		}
	}
	for(register int i(0) ; i<=11 ; i=-~i) a[i][0] = a[0][i] = a[11][i] = a[i][11] = 2;
	for(register int i(1) ; i<=10 ; i=-~i){
		for(register int j(1) ; j<=10 ; j=-~j){
			if(a[i][j]!=1 && (a[i][j-1] == 2 || a[i-1][j] == 2)) a[i][j] = 2;
		}
	}
	for(register int i(10) ; i>=1 ; i--){
		for(register int j(10) ; j>=1 ; j--){
			if(a[i][j] != 1 && (a[i+1][j] == 2 || a[i][j+1]== 2)) a[i][j] = 2;
		}
	}
	for(register int i(1) ; i<=10 ; i=-~i){
		for(register int j(1) ; j<=10 ; j=-~j){
			if(a[i][j]== 0) ans++;
		}
	}
	printf("%d",ans);    
	return 0;
}

2.奇怪的电梯

大楼的每一层楼都可以停电梯,而且第 i 层楼(1<=i<=N)上有一个数字 Ki(0<=Ki<=N)。
电梯只有四个按钮:开,关,上,下。上下的层数等于当前楼层上的那个数字。当然,如果
不能满足要求,相应的按钮就会失灵。例如:3 3 1 2 5 代表了 Ki(K1=3,K2=3,......),从一
楼开始。在一楼,按“上”可以到 4 楼,按“下”是不起作用的,因为没有-2 楼。那么,
从 A 楼到 B 楼至少要按几次按钮呢?

一道广搜的经典题,存两个状态,上和下,接着搜就行

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48 ; ch=getchar();}
	return x*f;
}
int n,a,b;
int e[10010],vis[10010];
queue<int>f;
queue<int>s;
int main(){	
	n=read();a=read();b=read();
	for(int i=1 ; i<=n ; i++) e[i] = read();
	memset(vis,0,sizeof(vis));
	f.push(a);s.push(0);
	vis[a] = 1;
	while(!f.empty()){
		if(f.front() == b){
			cout << s.front();
			return 0;
		}
		int x = f.front() + e[f.front()];
		if(x<=n && vis[x] == 0){
			vis[x] = 1;
			f.push(x);
			s.push(s.front() + 1);
		}
		x = f.front() - e[f.front()];
		if(x>=1 && vis[x] == 0){
			vis[x] = 1;
			f.push(x);
			s.push(s.front() + 1);
		}
		f.pop();
		s.pop();
	}
	cout << -1;
	return 0;
}

3.产生数

给出一个整数 n(n<=2000)和 k 个变换规则(k≤15)。规则:
① 1 个数字可以变换成另 1 个数字;
② 规则中,右边的数字不能为零。
例如:n=234,k=2 规则为
2 → 5
3 → 6
上面的整数 234 经过变换后可能产生出的整数为(包括原数)234,534,264,564 共 4
种不同的产生数。
求经过任意次的变换(0 次或多次),能产生出多少个不同的整数。仅要求输出不同整
数个数。

这道题比洛谷上的简单,数据范围调小了, 考虑这个数的每一位,如果能变换的话答案加一,记录下来,一直往下找,知道队列为空

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48 ; ch=getchar();}
	return x*f;
}
int n,k;
queue<int>q;
int cnt;
int x[20010],y[20010];
int vis[20010];
void bfs(){
	q.push(n);
	vis[n] = 1;
	while(!q.empty()){
		int a = q.front();
		int z = a,sum = 1;
		q.pop();
		while(a>0){
			int b = a%10;
			a /= 10;
			for(register int i(1) ; i<=k ; i=-~i){
				if(b== x[i]){ 
					int jilu = z - x[i]*sum + y[i]*sum;
					if(!vis[jilu]){
						vis[jilu] = 1;
						q.push(jilu);
						cnt++;
					}
				}
			}
			sum *= 10;
		}
	}
}
int main(){
	scanf("%d%d",&n,&k);
	for(register int i(1) ; i<=k ; i=-~i)scanf("%d%d",&x[i],&y[i]);
	bfs();
	printf("%d",cnt+1);
	return 0;
}

4.家庭问题

有 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}单独为
一个家庭,第一个家庭的人数为最多。

第一眼看上去肯定是一个并查集的题,于是我先拿并查集交了一遍,AC了

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48 ; ch=getchar();}
	return x*f;
}
int n,k;
int f[110];
int ans[110];
int cnt;
int maxn = -1e9;
int find(int x){
	if(f[x] == x) return x;
	return f[x] = find(f[x]);
}
int main(){
	cin >> n >> k;
	for(register int i(1) ; i<=n ; i=-~i) f[i] = i;
	for(register int i(1) ; i<=k ; i=-~i){
		int x,y;
		cin >> x >> y;
		f[find(x)] = find(y);
	}
	for(register int i(1) ; i<=n ; i=-~i){
		if(ans[f[find(i)]] == 0) ans[f[find(i)]]++,cnt++;
		else ans[f[find(i)]]++;
	}
	for(register int i(1) ; i<=n ; i=-~i) maxn = max(maxn,ans[i]);
	printf("%d %d",cnt,maxn);
	return 0;
}

但比赛的题目是队列,这么做。。(毕竟不太好),所以我就用队列广搜做了一遍

首先是存,用链式前向星存,注意是无向边,然后一个个枚举该点能走到的点,如果这个点未被走到,答案加一,并且用maxn记录家庭的最大数

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48 ; ch=getchar();}
	return x*f;
}
int n,k;
int cnt;
int ans1,ans2,maxn;
struct egde{
	int to,net;
}e[100010];
int head[100010];
bool vis[100010];
void add(int u,int v){
	e[++cnt].to = v;
	e[cnt].net = head[u];
	head[u] = cnt;
}
void bfs(int x){
	if(vis[x]) return;
	queue<int>q;
	vis[x] = 1;
	ans1++;
	ans2 = 1;
	q.push(x);
	while(!q.empty()){
		int k = q.front();
		q.pop();
		for(register int i=head[k] ; i ; i=e[i].net){
			if(!vis[e[i].to]){
				vis[e[i].to] = 1;
				q.push(e[i].to);
				ans2++;
			}
		}
	}
	maxn = max(maxn,ans2);
}
int main(){
	n=read();k=read();
	for(register int i(1) ; i<=k ; i=-~i){
		int x,y;
		x=read();y=read();
		add(x,y);
		add(y,x);
	}
	for(register int i(1) ; i<=n ; i=-~i) bfs(i);
	printf("%d %d",ans1,maxn);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值