zoukankan      html  css  js  c++  java
  • 2020.10.18:YC中学模拟赛

    2020.10.18:YC中学模拟赛
    (难度介于CSP-J2~CSP-S2)

    纪念品分组

    传送门

    讲解

    水题,但写sort人傻了,忘了sort是左闭右开的结构,导致数组没排完序 (分数-40)

    题意就是将N件物品2个一组,让求组数最少时,每组价值差尽量小
    具体怎么做呢?

    考试的时候,我是一开始想到的是用最小价值的物品和最大价值的物品相加,次小和次大相加,第K小的和第K大的相加,这样必定每组价值差最小

    sort(a,a+n+1);
    int l=1,r=n;
    while(l<=r){
    	l++;
    	r--;
    	ans++;
    }
    

    在这里插入图片描述

    但如果某两数之和大于价值上限怎么办?
    所以进行判断,单独取出这两个数中较大的一个,独成一组;而较小的一个参与与其他数字的合并
    在这里插入图片描述
    这是满足贪心的思想的

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int mx;//每组纪念品价格之和的上限
    int n;//购来的纪念品的总件数
    int a[30100];
    int ans;
     
    int main(){
    	//freopen("souvenir.in","r",stdin);
    	//freopen("souvenir.out","w",stdout);
    	cin>>mx>>n;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	sort(a,a+n+1);
    	int l=1,r=n;
    	while(l<=r){
    		if(a[l]+a[r]>mx){
    			r--;
    			ans++;
    		}else{//a[l]+a[r]<=mx
    			l++;
    			r--;
    			ans++;
    		}
    		
    	}
    	cout<<ans;
    	return 0;
    }
    

    开闭区间

    顺便插一句,sort一类的STL都是左闭右开的结构

    左闭右开:一种区间结构
    ( 开区间 ):区间两处的端点值取不到
    [ 闭区间 ]:区间两处的端点值可以取到

    所以,我就是忘了sort是左闭右开的那个人,然后就给下标0~n-1的数据排序,唯独没到下标n

    sort(a,a+n);
    

    城市互通

    传送门

    讲解

    就是有N个点M条边,然后看这些点边构成了多少个集合,最后-1(看需要连多少条边)就好了
    我想的是用并查集来做 (就构建集合,然后查找,比并查集模板还简单

    也没什么说的,就将每个点挂到自己的根节点上
    最后随便数一下有多少个根节点就完成

    不会并查集的同学请看看这篇文章:【并查集】一种与时间赛跑的巧妙算法
    以及学习并查集请必需掌握的链式前向星:关于路径存储的常见优化——前向星与链式前向星

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m;//N个城,M条路 
    int fa[100100];
    
    int find(int i){
    	if(i==fa[i]){//根节点 
    		return i;
    	}
    	else{
    		int x=find(fa[i]);
    		fa[i]=x;
    		return x;
    	}
    }
    int main(){
    	//freopen("city.in","r",stdin);
    	//freopen("city.out","w",stdout);
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)fa[i]=i;
    	for(int i=1;i<=m;i++){
    		int x,y;
    		cin>>x>>y;//x -- y
    		
    		fa[find(x)] = find(y);
    		
    	}
    	long long ans=0;
    	for(int i=1;i<=n;i++){
    		if(find(i)!=find(i-1)){
    			fa[find(i)]=find(i-1);
    			ans++;
    		}
    	}
    	ans--;
    	cout<<ans;
    	
    	return 0;
    }
    

    游荡的奶牛

    传送门

    讲解

    就是一张NM的地图,为障碍物,求奶牛T步内从[sx,sy]到[ex,ey]的方案数

    DFS

    我最开始打了个DFS搜索,以为T<=15数据能过

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,t;
    char a[110][110];
    int sx,sy,ex,ey;
    
    int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    
    bool vis[110][110];
    
    int ans;
    
    bool in(int x,int y){
    	return 0<x&&x<=n&&0<y&&y<=m;
    }
    
    void dfs(int x,int y,int z){//[x,y],第z秒 
    	if(z>t)return;
    	if(x==ex&&y==ey){
    		ans++;
    	}
    	//cout<<x<<" "<<y<<endl;
    	for(int i=0;i<4;i++){
    		int tx=x+dir[i][0];
    		int ty=y+dir[i][1];
    		if(in(tx,ty)&&vis[tx][ty]==0&&a[tx][ty]!='*'&&z<t){
    			vis[tx][ty]=1;
    			dfs(tx,ty,z+1);
    		}
    	}
    	vis[x][y]=0;
    	return;
    }
    
    int main(){
    	//freopen("cow.in","r",stdin);
    	//freopen("cow.out","w",stdout);
    	cin>>n>>m>>t;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			cin>>a[i][j];
    		}
    	} 
    	cin>>sx>>sy>>ex>>ey;
    	dfs(sx,sy,0);
    	cout<<ans;
    	return 0;
    }
    
    

    下来大佬YJA告诉我,这样时间复杂度高达约O(4^K)(4个方向,可以走T步,最坏约为10 ^9)

    所以我们进行记忆化

    以及,我们还要考虑目前所在的点和终点间的距离(这里用曼哈顿距离进行估价,即|X1-X2|+|Y1-Y2|) 是否大于T-走过的步数
    (即:|X1-X2|+|Y1-Y2|<=t-z)
    若大于那么从起点走T次后一定无法到达终点,所以后面一切均为无用功,直接结束本次搜索(可行性剪枝)

    DP

    可以用记忆化就可能能用DP

    DP有个好处就是可以不进行可行性剪枝
    而改用三维数组,某一维记录当前步数

    在T步内,到达[i,j]方案数为上下左右除去障碍物的和
    在这里插入图片描述
    然后判断是否越界等基本操作,给f[sx,sy]赋初值=1

    f[i][j][k] 表示第k时间到达(i,j)的方案数,得到:f[x][y][k]+=f[x+dir[0][i]] [y+dir[1][i]] [k+1]

    //dir表方向变化

    代码

    DP

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,t;
    int sx,sy,ex,ey;
    char a[110][110];
    int f[110][110][110];
    int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
    bool in(int x,int y) {
    	return 0<x&&x<=n&&0<y&&y<=m;
    }
    
    int main() {
    	cin>>n>>m>>t;
    	for(int i=1; i<=n; i++) {
    		for(int j=1; j<=m; j++) {
    			cin>>a[i][j];
    		}
    	}
    	cin>>sx>>sy>>ex>>ey;
    	f[sx][sy][0]=1;
    	for(int i=1; i<=t; i++) {
    		for(int j=1; j<=n; j++) {
    			for(int k=1; k<=m; k++) {
    				if(a[j][k]!='*') {
    					for(int l=0; l<4; l++) {
    						int tx=j+dir[l][0];
    						int ty=k+dir[l][1];
    						if(in(tx,ty)&&a[tx][ty]!='*') {
    							f[j][k][i]+=f[tx][ty][i-1];
    						}
    					}
    				}
    			}
    		}
    	}
    
    	cout<<f[ex][ey][t]<<endl;
    //	for(int k=1; k<=t; k++) {
    //		for(int i=1; i<=n; i++) {
    //			for(int j=1; j<=m; j++) {
    //				cout<<f[i][j][k]<<" ";
    //			}
    //			cout<<endl;
    //		}
    //		cout<<endl;
    //	}
    	return 0;
    }
    

    理发

    传送门
    线段树,暂时不太懂
    略......
    考试的时候暴力,A了两组数据,其他超时
    在这里插入图片描述

    //A两组数据
    #include<bits/stdc++.h>
    using namespace std;
    long long n;
    long long a[10100];
    long long ans;
    int main() {
    	//freopen("haircut.in","r",stdin);
    	//freopen("haircut.out","w",stdout);
    	cin>>n;
    	for(int i=1; i<=n; i++) {
    		cin>>a[i];
    	}
    	cout<<0<<endl;
    	for(int k=1; k<n; k++) {
    		ans=0;
    		for(int i=1; i<=n; i++) {
    			for(int j=1; j<i; j++) {
    				int x=a[i];
    				int y=a[j];
    				if(x>k)x=k;
    				if(y>k)y=k;
    				if(y>x){
    					ans++;
    					//cout<<ans<<" ";
    				}
    			}
    		}
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux 进程间通信(包含一个经典的生产者消费者实例代码)
    Linux多进程编程实例
    web开发中的mysql使用
    Linux 网络编程中的read和write函数正确的使用方式
    Linux 使用tcpdump观察arp通信过程
    Linux 开启echo等服务
    Linux send和recv
    自己动手写http服务器——主程序(三)
    自己动手写http服务器——线程池(一)
    http请求报文格式和响应报文格式
  • 原文地址:https://www.cnblogs.com/pqh-/p/13872280.html
Copyright © 2011-2022 走看看