week 7;

本文解析了SMU2024春季编程竞赛中的四个题目,涉及连续因子计算、最短路径算法、并查集在连通性和朋友关系判断中的应用,以及病毒溯源的图论方法。
摘要由CSDN通过智能技术生成

7-5 6翻了 - SMU 2024 spring 天梯赛2 (pintia.cn)

6翻了 :

不能用scanf()!=EOF,输入停不下来,用string a,getline(cin,a),读入整个字符串

先判段不为6得字符,直接输出,如果有六,判断有几个连续的六,根据题目要求输出;

注意,如果在循环里面加加,输出数字的时候会跳过读入下一个空格

#include<bits/stdc++.h>
using namespace std;
signed main(){
	string a;
	int j=0;
	getline(cin,a);
	for(int i=0;i<a.size();){
        if(a[i]!='6'){
            cout<<a[i];
        i++;
        }
		else if(a[i]=='6'){
			 j=i;
			while(a[j]=='6'){
				j++;
			}
			if(j-i>9){
				cout<<"27";
				i=j;
				continue;
			}
			else if(j-i>3){
				cout<<"9";
				i=j;
				continue;
			}
            else for(;i<j;i++)cout<<'6';
		}
		
		
	}
	return 0;
}


连续因子:

7-8 连续因子 - SMU 2024 spring 天梯赛3(补题) (pintia.cn)

知识点:连续12个数字相乘,最小为都有4e9,而2的31次方约等于2e9;

所以可以暴力循环,

如果给的数是素数,就直接输出最长长度是1,最小连续序列是他本身,

如果不是素数,从2开始循环,在用一个for循环,定义一个s,表示连续数字相乘的结果,结束条件为累乘结果大于n;长度相同时,只存在一个最小连续因子序列。

注意:长度len要初始化,start 也是

#include<bits/stdc++.h>
using namespace std;
#define int long long int
bool prime(int x){
	for(int i=2;i<=sqrt(x);i++){
		if(x%i==0){
			return 0;
		}
	 return 1;
	}
}
signed main()
{
	int n,len=0,start=0;
	cin>>n;
	int s=0;
	if(prime(n))cout<<1<<endl<<n<<endl;
	else {
		for(int i=2;i<=sqrt(n);i++){
			s=1;
			for(int j=i;j*s<=n;j++){
				s*=j;
				if(n%s==0&&j-i+1>len){
						start=i;
					len=j-i+1;
				
				}
			}
		}
		cout<<len<<endl;
		for(int i=start;i<start+len;i++){
			if(i==start)cout<<i;
			else cout<<"*"<<i;
		}
	}
	
	return 0;
}

哈利·波特的考试:

7-9 哈利·波特的考试 - SMU 2024 spring 天梯赛3(补题) (pintia.cn)

求最短路算法floyd:最初始的表(点到点的距离)0行0列不会有变化,对角线数字不会有变化,

题目要求找到一种动物可以变为任何一种动物,且要求魔咒最短,(例:不是鼠——>猫——>鱼,而是鼠——>猫,鼠——>鱼,),所以求出每一种动物变成其他动物的最短字符数,在最短路表中找出每一种动物变为最长字符的数字,每种动物的最长字符取最小的即是答案

#include<bits/stdc++.h>
using namespace std;
int n,m;	
int g[105][105];
void floyd(){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=n;k++){
				if(g[k][j]>g[j][i]+g[i][k]&&k!=i&&k!=j&&i!=j){
					g[k][j]=g[j][i]+g[i][k];
				}
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			g[i][j]=0x3f3f3f;
		}
	}
	for(int i=1;i<=m;i++){
		int a,b,c;
		cin>>a>>b>>c;
		g[a][b]=c;
		g[b][a]=c;
	}
	floyd();
	int dist[105];
	memset(dist,0,sizeof(dist));
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dist[i]<g[i][j]&&i!=j){
				dist[i]=g[i][j];
			}
		}
	}
	int form=0;
	int maxx=0x3f3f3f;
	for(int i=1;i<=n;i++){
		if(maxx>dist[i]){
		maxx=dist[i];
			form=i;	
		}
	}
	if(maxx==0x3f3f3f)cout<<"0";
	else cout<<form<<" "<<dist[form];
	
}

 文件传输:

7-12 文件传输 - SMU 2024 spring 天梯赛3(补题) (pintia.cn)

并查集:

找父亲结点用findd(x)!!!!不是fa[x];

#include<bits/stdc++.h>
using namespace std;
int fa[10004];
int findd(int x){
	if(fa[x]==x)return x;
	return fa[x]=findd(fa[x]);
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<=n;i++){
		fa[i]=i;
	}
	for(int i=0;;i++){
		char a;
		int b,c;
		cin>>a;
		if(a=='S')break;
		cin>>b>>c;
		if(a=='I'){
			fa[findd(c)]=findd(b);
		}
		else{
			if(findd(c)==findd(b))cout<<"yes"<<endl;
			else cout<<"no"<<endl;
		}
		
	
	}
	int sum=0;
	for(int i=1;i<=n;i++){
		if(fa[i]==i){
			sum++;
		}
	}
	
		if(sum==1)cout<<"The network is connected.";
		else cout<<"There are "<<sum<<" components."<<endl;
		
	
	return 0;
}

病毒溯源:

7-11 病毒溯源 - SMU 2024 spring 天梯赛3(补题) (pintia.cn)

图论题+dfs:

 因为题目要求如果长度一样就要输出序列最小,所以建图的时候用set默认从小到大进行存图;

用dfs来检测最深深度,

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+20;
int n,k;
set<int>v[N];
int st[N];//标记是否为儿子结点
int dep[N];//记录最长深度
int fa[N];//记录父亲结点;
int ans[N];//记录最长长度的最小卢携
int root,maxn;//最长深度
int maxi;//记录最低端的儿子
void dfs(int u){
	for(auto son:v[u]){//son是u的儿子
		dep[son]=dep[u]+1;
		if(dep[son]>maxn)maxn=dep[son],maxi=son;
		dfs(son);
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>k;
		for(int j=1;j<=k;j++){
			int u;
			cin>>u;
			v[i].insert(u);
			fa[u]=i;//记录每个结点的父节点
			st[u]=1;//记录哪些点儿子,要找出唯一的根节点
		}
		
	}
	for(int i=0;i<n;i++){
		if(!st[i])root=i;
		//找出父节点
	}
	maxn=1;//初始化最长长度
	maxi=root;//初始化根节点
	dep[root]=1;//初始化长度。记录每个点的深度
	dfs(root);
	int pos=maxi;//从最底端的结点网上找;
	cout<<maxn<<endl;
	for(int i=maxn;i>=1;i--){
		ans[i]=pos;
		pos=fa[pos];
	}
	for(int i=1;i<=maxn;i++){
		cout<<ans[i];
		if(i!=maxn-1)cout<<" ";
		
	}
	return 0;
}

估值一亿的AI代码:

7-7 估值一亿的AI核心代码 - SMU 2024 spring 天梯赛2(补题) (pintia.cn)

 用reverse将字符反转去掉开头和结尾的空格,用isalpha()和isdigit()函数判断空格两边是否为数字或者字符,在主函数里可以写一个auto f=[&](const string& k,const string &v )调用他;。。。,如果需要更改内容,需要判断两边是否为字母或者数字,或者是否在边界;

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



int main () {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin >> n;
    string s;
    getline(cin, s);
    
    while (n--) {
        getline(cin, s);
        cout << s << "\nAI: ";
        while (s.back() == ' ') s.pop_back();
        reverse(s.begin(), s.end());
        while (s.back() == ' ') s.pop_back();
        reverse(s.begin(), s.end());
        
        string ans;
        
        int cnt = 0;
        for (auto& c : s) {
            if (c == ' ') {
                cnt++;
            } else if (isalpha(c) || isdigit(c)) {
                if (cnt) ans += ' ';
                if (isupper(c) && c != 'I') c -= 'A' - 'a';
                ans += c;
                cnt = 0;
            } else {
                if (c == '?') c = '!';
                ans += c;
                cnt = 0;
            }
        }
        
        auto f = [&] (const string& k, const string&v) {
            int now = -1;
            while ((now = ans.find(k, now + 1)) != ans.npos) {
                int ok = 0;
                if (now - 1 < 0 || !isalpha(ans[now-1]) && !isdigit(ans[now-1])) {
                    ok++;
                }
                if (now + k.size() >= ans.size() || !isalpha(ans[now + k.size()]) && !isdigit(ans[now + k.size()])) {
                    ok++;
                }
                if (ok == 2) {
                    ans.erase(now, k.size());
                    ans.insert(now, v);
                }
            }
        };
        
        f("can you", "IS can");
        f("could you", "IS could");
        f("I", "you");
        f("me", "you");

        for (int i = 0; i < ans.size(); i++) {
            cout << ans[i];
            if (ans[i] == 'I' && i + 1 < ans.size() && ans[i+1] == 'S') {
                i++;
            }
        }
        cout << '\n';

        
        
    }

红色警报:

7-10 红色警报 - SMU 2024 spring 天梯赛2(补题) (pintia.cn)

用并查集解决此类(连通)问题;

每一次就开始攻占之前,做一次并查集,求出有几个不连通的量,攻占城市之后,标记该城市,然后对未标记的城市做一遍并查集,判断此时的根节点和之前的比较有没有减少;设攻占之前的节点数为before,攻占之后的节点数为after,如果before==after则说明攻占没有破坏他的连通性,如果after<before说明被破坏的城市为孤立城市,也不会报警,但若是before<after 结点的增加说明连通性被破坏了,则需要抱紧;他删了那个点是不会复原的。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 505;
int fa[MAXN],n,m,k,ans;
bool vis[MAXN];
struct node
{
	int x,y;
}no[5005];
int find(int x)
{
	if(fa[x] == x) return x;
	else return fa[x] = find(fa[x]);
}
void Union(int x,int y)
{
	int xx = find(x);
	int yy = find(y);
	if(xx != yy)
		fa[xx] = yy;
}
int main()
{
	int city;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)fa[i] = i;
	for(int i=1;i<=m;++i)
	{
		scanf("%d%d",&no[i].x,&no[i].y);
		Union(no[i].x,no[i].y);
	}
	for(int i=0;i<n;++i)if(fa[i]==i) ans++;//记录有几个不连通的点
	scanf("%d",&k);
	while(k--)
	{
		int cnt = 0;
		scanf("%d",&city);
		vis[city] = 1;
		for(int i=0;i<n;++i) fa[i] = i;
		 
		for(int i=1;i<=m;++i){
			if(!vis[no[i].x] &&!vis[no[i].y])
				Union(no[i].x,no[i].y);
		}
		
		for(int i=0;i<n;++i) if(!vis[i]&&fa[i]==i) cnt++; 
		if(cnt <= ans)
			printf("City %d is lost.\n",city);
		else
			printf("Red Alert: City %d is lost!\n",city);
		ans = cnt;
		if(ans == 0)
		{
			printf("Game Over.\n");
			return 0;
		}
	}
	return 0;
}

 

排座位:

7-11 排座位 - SMU 2024 spring 天梯赛2(补题) (pintia.cn)

并查集:

朋友的朋友也是我的朋友!!!!!!!!!!!!!!!!!!!!!!!!!!!!

#include <bits/stdc++.h>
using namespace std;
int fa[105];
int enemy[105][105];
int find(int x){
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
int main(){
	int n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	for(int i=1;i<=m;i++){
		int a,b,c;
		cin>>a>>b>>c;
		
		if(c==-1){
			enemy[a][b]=1;
			enemy[b][a]=1;
		}
		else{
			if(find(a)!=find(b)){
				fa[find(b)]=find(a);
			}
		}
	}
	for(int i=1;i<=k;i++){
		int x,y;
		cin>>x>>y;
		if(find(x)==find(y)&&enemy[x][y]==0){
			cout<<"No problem"<<endl;
		}
		else if(find(x)==find(y)&&enemy[x][y]==1){
			cout<<"OK but..."<<endl;
		}
		else if(find(x)!=find(y)&&enemy[x][y]==0){
			cout<<"OK"<<endl;
		}
		else if(find(x)!=find(y)&&enemy[x][y]==1)
			cout<<"No way"<<endl;
	}
	return 0;
}

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值