第六届浙江省高校程序设计竞赛

博客详细解析了ZOJ-3202、3203、3204等竞赛题目,涉及最大值下标寻找、数学应用、三分法求极值和最小生成树问题。通过克鲁斯卡尔算法解决网络连接问题,并提供了关键单词匹配的解题思路。
摘要由CSDN通过智能技术生成

ZOJ-3202

题目http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3202

分析:找出最大值的下标跟次小值

#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1007;
int b[maxn];
struct node{
	int id,num;
}a[maxn];
int cmp(node a1,node b1){
	return a1.num>b1.num;
}
int main(){
	int n;
	int T;
	scanf("%d",&T);
	while(T--){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i].num);
		a[i].id=i+1;
	}
	sort(a,a+n,cmp);
	printf("%d %d\n",a[0].id,a[1].num);
	}
	
	return 0;
}
ZOJ-3203

题目http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3203


分析:数学很重要,一直再用三角形相似,加上极端情况,忽略了关键一步,可以用均值不等式啊,痛~

详细解答--->>>

题意:

首先给出T组数据,每组给出灯离地面高度H,人的身高h,灯跟墙的距离D,人站在不同位置,影子的长度都不一样,求出最长的影子的长度。

题解:

计算出来的这条式子,可以直接进行三分,求出极值点,但是同样,我们可以通过这条公式用O(1)的方法求出来

三分写法:求最值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const double esp=1e-8;
double H,h,D;
double cal(double x)
{
	return D-x+H-(H-h)*D/x;
}
double three_devide(double l,double r)
{
	double left=l,right=r,mid,midmid;
	while (left+esp<right)
	{
		mid=(right+left)/2;
		midmid=(right+mid)/2;
		if (cal(mid)>=cal(midmid))
			right=midmid;
		else
			left=mid;
	}
	return cal(right);
}
int main()
{
    int T;
	scanf("%d",&T);
	while (T--)
    {
        scanf("%lf%lf%lf",&H,&h,&D);
        double l=D-h*D/H,r=D;
        double ans=three_devide(D-h*D/H,r);
        printf("%.3f\n",ans);
    }
	return 0;
}
公式法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const double esp=1e-8;
double H,h,D;
int main()
{
	int T;
	scanf("%d",&T);
	while (T--)
	{
		scanf("%lf%lf%lf",&H,&h,&D);
		double mx=D-h*D/H;
		if (D>=sqrt((H-h)*D) && mx<=sqrt((H-h)*D))
            mx=D+H-2*sqrt((H-h)*D);
		else if (sqrt((H-h)*D)<mx)
            mx=h*D/H;
        else
            mx=h;
		printf("%.3lf\n",mx);
	}
	return 0;
}
#include<stdio.h> 
int main(){
    int T;
	scanf("%d",&T);
    while(T--){
        double H,h,D;double ans=0;
        scanf("%lf%lf%lf",&H,&h,&D);
        for(double i=0;i<=h;i+=0.0005){
            double w=i+D*(h-i)/(H-i);
            if(w>ans)
                ans=w;
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}
ZOJ3204

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3204

题目大意:题目大意:有几台电脑,怎么用最少的费用把他

           们连接起来

   

解题思路:最小生成树问题。先将边从小到大排序,依次把

           边两端的点用并查集合并。需要注意的是,题目中

           给出的矩阵上三角和下三角是相同的,即只需处理

           一半就可以啦。

          克鲁斯卡尔算法

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
	int a,b;
	int n;
}edge[10005];
struct rea{
	int a,b;
}relans[500];
int father[105];
int cmp(struct node a,struct node b){
	if(a.n==b.n){
		if(a.a==b.a){
			return a.b<b.b;
		}
		else return a.a<b.a;
	}
	return a.n<b.n;
}

int cmp1(struct rea x,struct rea y){
	if(x.a==y.a) return x.b<y.b;
	else return x.a<y.a;
}

int Find(int n){
	if(father[n]==n) return n;
	else return father[n]=Find(father[n]);
}

int main(){
	int t,i,j;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		int k=0;
		for(i=1;i<=n;i++) father[i]=i;
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
				int tmp;
				scanf("%d",&tmp);
				if(tmp!=0){
					edge[k].a=i;
					edge[k].b=j;
					edge[k++].n=tmp;
				}
			}
		}
		sort(edge,edge+k,cmp);
		int ans=0;
		for(i=0;i<k;i++){//并查集 
			int ta=Find(edge[i].a);
			int tb=Find(edge[i].b);
			if(ta!=tb){
				father[ta]=tb;
				relans[ans].a=edge[i].a;
				relans[ans].b=edge[i].b;
				ans++;
			}
			if(ans==n-1) break;//满足树的性质
		}
		sort(relans,relans+ans,cmp1);
		if(ans==n-1){
			for(i=0;i<ans;i++){
				if(i==0)
					printf("%d %d",relans[i].a,relans[i].b);
				else 
					printf(" %d %d",relans[i].a,relans[i].b);
			}
			printf("\n");
		}
		else{
			printf("-1\n");
		}
	}
	return 0;
}
ZOJ3207

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3370


输入:第一行为一个正整数N(1<=N<100)。以下N行每行一个关键单词,由字母,数字或下划线构成。接下来一个正整数K(1<=K<100)。以下K行每行第一个数为Ni,表示该行有Ni个单词,接下来是这Ni个单词,每个单词之间用空格分隔。

输出:对于K行的每一行,输出每行含有多少个关键单词。

分析:读入所有关键单词到map中去,然后对于每行依次判断每行中的单词是否在map中即可。


#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
map<string,int>mp;
int main(){
	mp.clear();
	int T;
	string str;
	scanf("%d",&T);
	while(T--){
		cin>>str;
		if(mp[str]==0){
			mp[str]++;
		} 
	}
	int k;
	int m,sum=0;
	string str1; 
	scanf("%d",&k);
	while(k--){
		sum=0;
		scanf("%d",&m);
		while(m--){
			cin>>str1;
			sum+=mp[str1];
		}
		printf("%d\n",sum); 
	} 
	return 0;
}

ZOJ3209

点击打开DLX讲解
学习---->>>点击打开链接+点击打开链接

ZOJ3210[水]


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=100007;
int a[maxn],b[maxn];
int main(){
 int T,N;
 cin>>T;
 while(T--){
  cin>>N;
  for(int i=0;i<N;i++){
   cin>>a[i];
  }
  for(int i=0;i<N;i++){
   cin>>b[i];
  }
  int flag=0,flag2=0;
  for(int i=0;i<N;i++){
   flag=0;flag2=0;
   if(a[i]==b[N-1-i]){
    flag=1;
   }
    if(a[i]==b[i]){
    flag2=1;
   }
  }
  if(flag==1&&flag2==1){
    cout<<"both"<<endl;
   } 
  
  else if(flag==1&&flag2==0){
    cout<<"stack"<<endl;
   }
  else if(flag2==1&&flag==0){
   cout<<"queue"<<endl;
  }
  else{
   cout<<"neither"<<endl;
  }
 }return 0;
} 

ZOJ3211 Dream City[动态规划DP]

JAVAMAN is visiting Dream City and he sees a yard of gold coin trees. There are n trees in the yard. Let's call them tree 1, tree 2 ...and tree n. At the first day, each tree i has ai coins on it (i=1, 2, 3...n). Surprisingly, each tree i can grow bi new coins each day if it is not cut down. From the first day, JAVAMAN can choose to cut down one tree each day to get all the coins on it. Since he can stay in the Dream City for at most m days, he can cut down at most m trees in all and if he decides not to cut one day, he cannot cut any trees later. (In other words, he can only cut down trees for consecutive m or less days from the first day!)

Given n, m, ai and bi (i=1, 2, 3...n), calculate the maximum number of gold coins JAVAMAN can get.

Input

There are multiple test cases. The first line of input contains an integer T (T <= 200) indicates the number of test cases. Then T test cases follow.

Each test case contains 3 lines: The first line of each test case contains 2 positive integers n and m (0 < m <= n <= 250) separated by a space. The second line of each test case contains n positive integers separated by a space, indicating ai. (0 < ai <= 100, i=1, 2, 3...n) The third line of each test case also contains n positive integers separated by a space, indicating bi. (0 < bi <= 100, i=1, 2, 3...n)

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Output

For each test case, output the result in a single line.

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Sample Input

2
2 1
10 10
1 1
2 2
8 10
2 3

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Sample Output

10
21

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Hint
s:
Test case 1: JAVAMAN just cut tree 1 to get 10 gold coins at the first day.
Test case 2: JAVAMAN cut tree 1 at the first day and tree 2 at the second day to get 8 + 10 + 3 = 21 gold coins in all.

关键:找出状态转移方程

分析:刚开始考虑复杂了,其实就是按照每天砍树从小到大排序,长的果子数从小到大排序,列出方程即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=300;
int dp[maxn][maxn];
struct tree
{
    int t,g;
} w[maxn];
int cmp(tree a,tree b)
{
    if(a.g==b.g) return a.t<b.t;
    else return a.g<b.g;
}
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
       scanf("%d %d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&w[i].t);
        }
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&w[i].g);
        }
        sort(w+1,w+1+n,cmp);

        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
                dp[i][j]=0;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+w[i].t+(j-1)*w[i].g);//dp[i][j]指前i棵树在前j天得到的最大值
        }
        int countt=0;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                if(dp[i][j]>countt)
                    countt=dp[i][j];
            }
        }
      printf("%d\n",countt);
    }
    return 0;
}
ZOJ3212 K-nice

This is a super simple problem. The description is simple, the solution is simple. If you believe so, just read it on. Or if you don't, just pretend that you can't see this one.

We say an element is inside a matrix if it has four neighboring elements in the matrix (Those at the corner have two and on the edge have three). An element inside a matrix is called "nice" when its value equals the sum of its four neighbors. A matrix is called "k-nice" if and only if k of the elements inside the matrix are "nice".

Now given the size of the matrix and the value of k, you are to output any one of the "k-nice" matrix of the given size. It is guaranteed that there is always a solution to every test case.

Input

The first line of the input contains an integer T (1 <= T <= 8500) followed by T test cases. Each case contains three integers n, m, k (2 <= n, m <= 15, 0 <= k <= (n - 2) * (m - 2)) indicating the matrix size n * m and it the "nice"-degree k.

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Output

For each test case, output a matrix with n lines each containing m elements separated by a space (no extra space at the end of the line). The absolute value of the elements in the matrix should not be greater than 10000.

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Sample Input

2
4 5 3
5 5 3

<b< style="background-color: transparent; border-radius: 0px; box-shadow: none; padding: 0px;" dd="">

Sample Output

2 1 3 1 1
4 8 2 6 1
1 1 9 2 9
2 2 4 4 3
0 1 2 3 0
0 4 5 6 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

题意:随便写个矩阵,满足题意即可

分析:用0,1矩阵。初始化为1,要想满足改为0即可。

#include<stdio.h>
int main()
{
	int t,n,m,k,a[15][15];
	int i,j,sum;
	scanf("%d",&t);
	while(t--)
	{
		sum=0;//当sum为k个时,说明已经放好了
		scanf("%d%d%d",&n,&m,&k);
		for(i=0;i<n;i++)
			for(j=0;j<m;j++)
				a[i][j]=1;
		for(i=1;i<n-1;i++)
			for(j=1;j<m-1;j++)
			{
				if(sum==k)break;
				else
				{
					a[i][j]=0;//中心
					a[i-1][j]=0;//上
					a[i+1][j]=0;//下
					a[i][j-1]=0;//左
					a[i][j+1]=0;//右
					sum++;
				}
			}
		for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
				if(j==0)
					printf("%d",a[i][j]);
				else
					printf(" %d",a[i][j]);
			printf("\n");
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值