首页 > 其他分享 >牛客挑战赛64

牛客挑战赛64

时间:2022-12-22 13:00:12浏览次数:57  
标签:递归 汉诺塔 int 牛客 xx 64 挑战赛 盘子 find

https://ac.nowcoder.com/acm/contest/42819

题目出得很好

分析:

很清晰的一道启发式合并 小集合合并到大集合

当 1 在大集合时 遍历小集合的时候就可统计答案

当 1 在小集合时 因为每个点最多只会统计一次答案 此时遍历大集合也能统计答案

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
#define int ll
const int maxn=2e5+5;
void solve();
int x,y,n,m1,m2,cnt;
int fa[maxn],ans[maxn];
vector<int>Q[maxn];
int find(int xx){
	if(fa[xx]!=xx)return fa[xx]=find(fa[xx]);
	return xx;
}
void add(int xx,int yy){
	int fx=find(xx),fy=find(yy),f1=find(1);
	if(fx==fy)return;
	if(Q[fx].size()<Q[fy].size())swap(fx,fy);
	if(f1==fy)
	for(int i=0;i<Q[fx].size();i++)
	ans[Q[fx][i]]=cnt;
	for(int i=0;i<Q[fy].size();i++){
		int to=Q[fy][i];
		Q[fx].push_back(to);
		if(fx==f1)ans[to]=cnt;
	}
	fa[fy]=fx;
	Q[fy].clear();
}
signed main(){
	int T;T=1;
	while(T--)solve();
     return 0;
}
void solve(){
	memset(ans,-1,sizeof(ans));
	ans[1]=0;
	cin>>n>>m1>>m2;
	for(int i=1;i<=n;i++)fa[i]=i,Q[i].push_back(i);
	for(int i=1;i<=m1;i++)cin>>x>>y,add(x,y);
	for(int i=1;i<=m2;i++)cin>>x>>y,cnt++,add(x,y); 
	for(int i=1;i<=n;i++)cout<<ans[i]<<endl;
}

分析:

汉诺塔问题的变种

先来看标准的汉诺塔问题

递归写法:

def move(n,A,B,C)://n个盘子放在A 经过B 放在C上
    if n==1:             # 1个盘子,直接打印出移动动作
        print(A,'--->',C)
    else:                # n > 1时,用抽象出的3步来移动
        move(n-1, A, C, B) #step1.  把除了最大的盘子之外的盘子从A移到B
        print(A,'--->',C) #step2.  把最大的盘子从A移到C
        move(n-1, B, A, C) #step3.  把除了最大的盘子之外的盘子从B移到C

打表时候就会发现 1 3 5 7 15

发现f[i]=f[i-1]×2+1

怎么理解这个式子

回到本题来

60的数据肯定和标准的汉诺塔一样 能够推出一个式子 20的数据递归输出方案

推来推去发现推不出式子来 然后写递归 发现也不会 我太菜了唉

递归:

根据汉诺塔的常规套路,将除了最大盘之外的盘子堆到除 最大盘所在柱 的另一个非目标柱上,然后将最大盘移动到目标柱上,不断递归下去即可

具体地说,假设当前需要将 i号盘从 s移动到 t柱,那么我们将 [1,i)号盘全部堆到除 s,t外的那个柱子上,然后再将 i号盘堆到 t上即可。

#include <bits/stdc++.h>

using namespace std;

int n, b[65];

void dfs(int k, int t) {
    if (b[k] == t) return ;
    for (int i = k - 1; i; i--) dfs(i, 3 - b[k] - t);
    b[k] = t, printf("%d %c\n", k, t + 'A');
}

int main() {
    scanf("%d", &n);
    for (int i = 2; i <= n; i += 2) b[i] = 2;
    for (int i = n; i; i--) dfs(i, 1);
    return 0;
}

标签:递归,汉诺塔,int,牛客,xx,64,挑战赛,盘子,find
From: https://www.cnblogs.com/wzxbeliever/p/16998316.html

相关文章