计算机学院大学生程序设计竞赛(2015’11)

1001 搬砖(dp)
题意:把N块砖每次分成两摞,每次消耗的体力是两摞砖的差值,直到每摞只剩下一块砖,求消耗的最少体力。
思路:一开始摸不到头脑,不明白题目的意思,后来和别人讨论,一来明白了和整除2有关,二来是清楚了用DP的思想,清楚了原理,就迎刃而解了。
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[10000005];

int main(){
	
	int t;
	cin>>t;
	memset(dp,0,sizeof(dp));
	dp[2]=0;
	dp[3]=1;
	for(int i=4;i<=10000005;i++){
		if(i%2==0)
			dp[i]=dp[i/2]+dp[i/2];
		else
			dp[i]=dp[i/2]+dp[i/2+1]+1;
	}
	while(t--){
		long long n;
		cin>>n;
		cout<<dp[n]<<endl;
	}
	return 0;
} 

1002 洗衣服(水题)
题意:给定n天,和每天要洗的衣服数量,还给定三个标准a,b,c。当衣服数量小于a时继续积攒,当大于a时就立刻拿去洗,且不同数量的衣服需要支付不同的金额。求支付的金额数。
思路:是一道简单的模拟题,但是要注意的有两点,一是每次洗衣服都是把所有的衣服洗完,二是用scanf和printf,防止超时。
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

int main(){
	
	int n,a,b,c;
	while(scanf("%d%d%d%d",&n,&a,&b,&c)!=EOF){
		int coin=0;
		int sum=0;
		for(int i=0;i<n;i++){
			int t;
			cin>>t;
			sum+=t;
			if(sum<a){
				continue;
			}
			else if(sum>=a&&sum<b){
				sum=0;
				coin+=2;
			}
			else if(sum>=b&&sum<c){
				sum=0;
				coin+=3;
			}
			else if(sum>=c){
				sum=0;
				coin+=4;
			}
		}
		printf("%d\n",coin);
	}
	return 0;
} 


1003 懒得写 暂空


1004 质方数(模拟)
题意:给定一个数m,求一个质数n,使n*n最接近m,输出n*n。
思路:先打出质数表,然后对m开方,找到大于和小于m的第一个质数进行比较,看谁的平方最接近m。需要注意的是要处理特殊情况,如果开方之后恰好为质数,直接输出其本身。如果开方之后为1,则输出4。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h> 
using namespace std;
int isprime[10010];
int prime[10010];

void is_Prime(){
	int cnt=0;
	isprime[0]=isprime[1]=1;
	for(int i=2;i<=10005;i++){
		if(isprime[i]==0)
			prime[cnt++]=i;
		for(int j=0;j<cnt&&prime[j]*i<=10005;j++){
			isprime[prime[j]*i]=1;
			if(i%prime[j]==0)
				break;
		}
	}
}

int main(){
	
	is_Prime();
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		cin>>n;
		int m=sqrt(n);
		//cout<<m<<endl;
		if(!isprime[m]){
			cout<<m*m<<endl;
		}
		else if(m==1)
			cout<<4<<endl;
		else{
			int a=m;
			int b=m;
			while(isprime[a]){
				a++;
			}
			while(isprime[b]){
				b--;
			}
			int sum=abs(n-a*a)<abs(n-b*b)?a*a:b*b;
			cout<<sum<<endl;
		}
	}
	return 0;
} 

1005 ACM组队安排(dp)
题意:组队情况可以为1人1组,2人1组和3人1组,求给定n个人有几种分组方式。
思路:一开始上网搜到了集合划分算法,后来听阿洁哥讲了一下是和DP有关的,最后看了一下阿洁哥的代码,实在是佩服..如果已经求出n-1个人的分组方式,要求n个人的分组方式,则这第n个人可以1人1组,则分组方式为dp[n-1],如果第n个人和前面n-1个人中一个人分成2人组,则为dp[n-2]*(n-1),同理如果和前面n-2中两个人分成3人组,则为dp[n-3]*Cn-1 2。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
using namespace std;
long long dp[25];

int main(){
	
	int n;
	dp[1]=1;
	dp[2]=2;
	dp[3]=5;
	for(int i=4;i<=20;i++)
		dp[i]=dp[i-1]+dp[i-2]*(i-1)+dp[i-3]*(i-1)*(i-2)/2;
	while(cin>>n&&n){
		cout<<dp[n]<<endl;
	}
	return 0;
} 

1006 懒得写 暂空

1007 油菜花王国(并查集)
题意:给定n个精灵和其能力值和m组关系,m组关系中给定两个数a,b,代表b精灵属于a精灵家族。如果家族中的精灵的能力值恰好为斐波那契数,则家族威望值+1。求最大的家族威望值。
思路:一上来就明确需要用到并查集+求斐波那契数。但是听信了别人的话选用了矩阵快速幂方法求斐波那契..其实根本用不到,因为第45项就已经超过题目要求的最大值了,所以直接递归求解就可以。坑爹在于提交了无数次都是WA...最后用阿洁哥的算法,即把威望在并查集的时候一起合并到父节点就AC了,也是醉...还要注意的是并查集最好返回的是f[x],如果返回x会超内存。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define ll long long
ll fibo[50];
int f[1050];
int fa[1050];
void init(){
    fibo[1] = 1;
    fibo[2] = 1;
    for(int i = 3; i <= 45; i++){
        fibo[i] = fibo[i-2] + fibo[i-1];
    }
}
int check(int n){
    for(int i = 1; i <= 45; i++){
        if(n == fibo[i])
            return 1;
        if(n < fibo[i])
            return 0;
    }
}
int find(int x)
{
    if(x != fa[x])
        fa[x] = find(fa[x]);
    return fa[x];
}
void merge(int x,int y)
{
    int a = find(x),b = find(y);
    if(a != b){
        fa[b] = a;
        f[a] += f[b];
    }
}
int main(){
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        int u,v,t;
        memset(f,0,sizeof(f));
        memset(fa,0,sizeof(fa));
        for(int i = 1; i <=n; i++){
            fa[i] = i;
            scanf("%d",&t);
            f[i] = check(t);
        }
        for(int i = 0; i < m; i++){
            scanf("%d%d",&u,&v);
            merge(u,v);            
        }
        int ans = 0;
        for(int i = 1; i <= 1000; i++){
            if(f[i] > ans){
                ans = f[i];
            }
        }
        printf("%d\n", ans);
    }
}

1008 游乐园(贪心)
题意:小明有k元,游乐场有n个项目,给定每个项目需要花费钱数,求小明的钱最多可以用来玩多少项目。前提条件是小明的朋友推荐了m个项目,这m个项目是小明必须玩的,如果连玩这m个项目的钱都不够,则输出-1。
思路:一开始想用01背包,但是钱数的最大值太大,导致开数组的话会超内存。后来发现用简单的贪心就可以,注意的就是m个项目的钱要减去,且把这m个项目的钱数置0,或者用标记数组置1。然后将其余项目的花费排序,从小到大判断能否满足。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h> 
using namespace std;
int cost[10005];

int main(){
	
	int t;
	scanf("%d",&t);
	while(t--){
		int n,m,k;
		int cnt=0;
		scanf("%d%d%d",&n,&m,&k);
		for(int i=1;i<=n;i++){
			scanf("%d",&cost[i]);
		}
		long long sum=0;//用long long不然会爆 
		for(int i=1;i<=m;i++){
			int a;
			scanf("%d",&a);
			sum+=cost[a];
			cost[a]=0;
		}
		if(sum<k){
			k-=sum;
			cnt+=m;
			sort(cost+1,cost+n+1);
			int i=0;
			while(cost[i]==0)
				i++;
			for(;i<=n;i++){
				if(cost[i]<k){
					k-=cost[i];
					cnt++;
				}
				else if(cost[i]==k){
					cnt++;
					break;
				}
				else
					break;
			}
			cout<<cnt<<endl;
		}
		else if(sum==k){
			cout<<m<<endl;
		}
		else{
			cout<<"-1"<<endl;
		}
		
	}
	return 0;
} 



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值