东华进阶oj71-100 【蓝桥杯】

本文详细介绍了东华进阶oj中71-100题目的内容,包括城市建设、最大子阵、动态规划等问题,涵盖了矩阵、路径规划、最优化等算法。同时给出了部分题目如最大子阵、矩阵乘法的解题思路和示例输入输出。
摘要由CSDN通过智能技术生成

71 城市建设
72 最大子阵
73 蚂蚁感冒 易 1
74 地宫取宝 易 1
75 斐波那契 易 1
76 小朋友排队 易 1
77 分糖果 易 1
78 兰顿蚂蚁 易 1
79 正则问题 易 1
80 分巧克力 易 1
81 日期问题 中 1
82 九宫幻方 易 1
83 拉马车 易 1
84 发现环 易 1
85 对局匹配 易 1
86 区间移位 易 1
87 矩阵翻硬币 易 1
88 邮局 易 1
89 包子凑数 易 1
90 波动数列 易 1
91 买不到的数目 易 1
92 促销购物 易 1
93 种树 易 1
94 能量项链 易 1
95 贪吃的大嘴 易 1
96 摆花 易 1
97 最长公共子序列 易 1
98 合并石子 易 1
99 矩阵乘法 易 1
100 fx权重 易 1

在这里插入图片描述
输入说明 :

输入的第一行包含两个整数n, m,分别表示C市中重要地点的个数和可以建设的道路条数。所有地点从1到n依次编号。
  接下来m行,每行三个整数a, b, c,表示可以建设一条从地点a到地点b的道路,花费为c。若c为正,表示建设是花钱的,如果c为负,则表示建设了道路后还可以赚钱(比如建设收费道路)。
  接下来一行,包含n个整数w_1, w_2, …, w_n。如果w_i为正数,则表示在地点i建设码头的花费,如果w_i为-1,则表示地点i无法建设码头。
  输入保证至少存在一个方法使得任意两个地点能只通过新修的路或者河道互达。

对于20%的数据,1<=n<=10,1<=m<=20,0<=c<=20,w_i<=20;
  对于50%的数据,1<=n<=100,1<=m<=1000,-50<=c<=50,w_i<=50;
  对于70%的数据,1<=n<=1000;
  对于100%的数据,1 <= n <= 10000,1 <= m <= 100000,-1000<=c<=1000,-1<=w_i<=1000,w_i≠0。

输出说明 :

输出一行,包含一个整数,表示使得所有地点通过新修道路或者码头连接的最小花费。如果满足条件的情况下还能赚钱,那么你应该输出一个负数。

比如:

输入

5 5
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1

输出

9

说明:
  建设第2、3、4条道路,在地点4、5建设码头,总的花费为9。
Kruscal:

#include<iostream>
#include<string>
#include<sstream>
#include <cmath>
#include<algorithm>
using namespace std;
 
struct edge{
   
    int u,v,val;
}e[1000000];;
 
int set_pos[10010]={
   0};  //被占用设为1
 
int N,M;
int N_pier=0;
 
struct pier{
   
    int u,val;
}p[100000];
 
int pier_num_0_connect=0;
int pier_num_0_array[10010]={
   0};
 
int change_land_road(int t){
   
    e[t].val=0;  return 0;
}
 
bool cmp(edge a,edge b){
   
	return a.val<b.val;
}
 
bool cmp_2(pier a,pier b){
   
	return a.val<b.val;
}
 
int find_min_path(){
   
    int min_money=100000;
    int x_tmp,y_tmp,t_tmp;
    int kind;// 1 表示陆地  2表示水路
 
    for(int i=1;i<=M;i++){
   
        if(set_pos[e[i].u]+set_pos[e[i].v]==1)  //判断是否一个在树内,一个在树外
        if(e[i].val < min_money){
   
            min_money=e[i].val;
            kind = 1;
            x_tmp = e[i].u;
            y_tmp = e[i].v;
            t_tmp = i;
            break;
        }
    }
 
    for(int i=1;i<=N_pier;i++)
        if(set_pos[0]+set_pos[p[i].u]==1)
        if(p[i].val < min_money){
   
                min_money=p[i].val;
                kind = 2;
                x_tmp = 0;
                y_tmp = p[i].u;
                t_tmp = i;
                break;
            }
 
    if(kind == 1){
    //陆路
        set_pos[x_tmp]=1;set_pos[y_tmp]=1;
        change_land_road(t_tmp);    //把选中的路权值设为0,这样最后还有权值为负的就分得清楚了
        return min_money;
    }
    if(kind == 2){
    //水路
 
        set_pos[x_tmp]=1;set_pos[y_tmp]=1;
        if(x_tmp == 0){
                //设置的额外的信号量,记录多少点与0点相连,如果最后只有一个,那么就要删去
            pier_num_0_array[pier_num_0_connect]=t_tmp;
            pier_num_0_connect++;
        }
        return min_money;
    }
}
 
 
int main(){
   
 
   cin >> N >> M;
   int total_money=0;
   int x=0;
 
    for(int i=1;i<=M;i++)
        cin >> e[i].u >> e[i].v >>e[i].val;
    for(int i=1;i<=N;i++){
   
        cin >> x;
        if(x>0){
   
            N_pier++;
            p[N_pier].u=i;
            p[N_pier].val=x;
        }
    }
 
    sort(e+1,e+M+1,cmp);
    sort(p+1,p+N_pier+1,cmp_2);
 
    set_pos[1]=1;
    for(int i=0;i<N;i++){
   
        total_money+=find_min_path();
    }
 
    //对于水路,滞后性处理
    if(pier_num_0_connect==1){
   
        int the_only_one_pier=pier_num_0_array[0];
        total_money-=p[the_only_one_pier].val;
    }
    //对于陆路的,滞后性处理
    for(int i=1;i<=M;i++){
   
      if(e[i].val < 0)
        total_money += e[i].val;
   }
 
    cout << total_money <<endl;
    return 0;
}

Prim:

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
 
#define MAXN 10005 
#define MAXM 100005
 
struct node{
   
	int u,v,w; 
}edge[MAXM+MAXN];  
 
int fa[MAXN];  
 
bool cmp(node a,node b)
{
   
	return a.w<b.w; 
}
 
int find(int x)
{
   
	if(x==fa[x]) return x; 
	return fa[x]=find(fa[x]);    
}
 
void init(int n)
{
   
	for (int i=0;i<=n;i++)
		fa[i]=i;  
} 
 
int kruscal(int n) 
{
   
	int fu,fv,w,sum=0;  
 
	for (int i=0;i<n;i++)
	{
    
		fu=find(edge[i].u);  
		fv=find(edge[i].v);  
		w=edge[i].w; 
		if (fu!=fv||w<0){
   
			sum+=w;   
			fa[fu]=fv; 
		}
	} 
	return sum; 
}
 
int route(int n,int m)
{
   
	init(n); 
	sort(edge,edge+m,cmp);   
	int ans=kruscal(m);    
	return ans;  
} 
 
int main()
{
   
	int n,m,cost,i,fu,fv,f,k,ans,ans1;   
	while (cin>>n>>m) 
	{
      
		for (i=0;i<m;i++)
			cin>>edge[i].u>>edge[i].v>>edge[i].w; 
 
		k=m; 
		for (i=1;i<=n;i++) 
		{
    
			cin>>cost; 
			if (cost!=-1) 
			{
    
				edge[k].u=0; 
				edge[k].v=i; 
				edge[k++].w=cost; 
			}
		}
 
		init(n); 
		for (i=0;i<m;i++) 
		{
      
			fu=find(edge[i].u);  
			fv=find(edge[i].v);  
			if (fu!=fv)
				fa[fu]=fv;  
		}
 
		f=find(1); 
		for (i=2;i<=n;i++)
		{
    
			if (f!=find(i)) 
				break; 
		}
 
		if (i==n+1)
		{
    
			ans=route(n,m);    //考虑码头(即考虑0点)
			ans1=route(n,k);   //不考虑码头
			if (ans>ans1)
				cout<<ans1<<endl; 
			else cout<<ans; 
 
			continue; 
		} 
 
		cout<<route(n,k)<<endl;   
	}
 
	return 0;  
}

72 最大子阵

问题描述 :

给定一个n*m的矩阵A,求A中的一个非空子矩阵,使这个子矩阵中的元素和最大。

其中,A的子矩阵指在A中行和列均连续的一块。

输入说明 :

输入的第一行包含两个整数n, m,分别表示矩阵A的行数和列数。
  接下来n行,每行m个整数,表示矩阵A。
  对于50%的数据,1<=n, m<=50;
  对于100%的数据,1<=n, m<=500,A中每个元素的绝对值不超过5000。

输出说明 :

输出一行,包含一个整数,表示A中最大的子矩阵中的元素和。

比如:

输入
3 3
-1 -4 3
3 4 -1
-5 -2 8

输出
10

说明:
  取最后一列,和为10。

#include <stdio.h> 
int main()
{
   
	int n,m;
	scanf("%d%d",&n,&m);
	int dp[501][501]={
   0};//初始化数组
	int i,j;
	int t;
	for(i=1;i<=n;i++)
	{
   
		for(j=1;j<=m;j++)
		{
   
			scanf("%d",&t);
			dp[i][j]=dp[i-1][j]+t;//dp存储的是当前所在位置前面的和(例如dp[2][1]=dp[0][0]+dp[1][0]+dp[2][0])
		}
	}
	/*算法逻辑*/
	int temp=0;
	int max=-99999;
	for(i=1;i<=n;i++)//循环一
	{
   
		for (j=1;j<=i;j++)//循环二   循环一和循环二实现的是矩阵行的组合
		{
   
			temp=0;
			for(int k=1;k<=m;k++)
			{
   
				temp=dp[i][k]-dp[j-1][k]+temp;//(dp[i][k]-dp[j-1][k])是第k列第i行到第j行的和
				if(temp>max)
					max=temp;
				if(temp<0)
					temp=0;
			}
		}
	}
	printf("%d",max);
	return 0;
}

在这里插入图片描述

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int a[1000]; 
int main(){
   
    int n;
    scanf("%d",&n);
    int i=0,j=0;
    int ans=1;
    for(i=0;i<n;i++)
    {
   
    	scanf("%d",&a[i]);
	}
	int x=a[0];
	if(x>0)//2
	{
   
		for(j=1;j<n;j++)
		{
   
			if(a[j]<0&&-a[j]>x)
			{
   
				ans++;    //2.1 
			}
		}
		if(ans!=1)	
		{
   
			  for(j=1;j<n;j++)
		      {
   
			    if(a[j]>0&&a[j]<x)
			   {
   
				ans++;    //2.2 
			   }
	    	  }
		}
	}
	if(x<0)//2
	{
   
		for(j=1;j<n;j++)
		{
   
			if(a[j]>0&&a[j]<-x)
			{
   
				ans++;    //2.3
			}
		}
		if(ans!=1)	
		{
   
			  for(j=1;j<n;j++)
		      {
   
			    if(a[j]<0&&-a[j]>-x)
			   {
   
				ans++;    //2.4
			   }
	    	  }
		}
		
	}
	printf("%d\n",ans);
	return 0;
}

在这里插入图片描述

/*
	T74 地宫寻宝 
	涉及到动态规划,深度优先搜索,四维数组,取余相关数学原理 
*/ 

#include<stdio.h>
#include<string.h>
#define MAX_SIZE 51

int n, m, k;
int map[MAX_SIZE][MAX_SIZE];// 宝物地图 
int dp[MAX_SIZE][MAX_SIZE][15][15];
int dfs(int x, int y, int sum, int max);

int main() {
   
	int i = 0, j = 0;
	
	scanf("%d%d%d", &n, &m, &k);
	for (i = 1; i <= n; i++) {
   
		for (j = 1; j <= m; j++) {
   
			scanf("%d", &map[i][j]);
		}
	}
	
	memset(dp, -1, sizeof(dp));// 初始化 
	printf("%d\n", dfs(1, 1, 0, -1)); 
	
	return 0;
} 

// 求方案的总数 
// x y sum max分别表示坐标(x, y),当前宝物数量,当前宝物最大价值 
int dfs(int x, int y, int sum, int max) {
   
	int plans = 0;// 从当前坐标到出口的方案总数 	
	
	if (dp[x][y][sum][max + 1] != -1) {
   // 当前坐标已经计算过,则直接返回结果 
		return dp[x][y][sum][max + 1];
	} 
	
	if (x == n && y == m) {
   // 地宫出口,也即递归出口 
		if (map[x][y] > max) {
   // 宝物价值大,可拿 
			if (sum == k || sum == k - 1) {
   // 宝物拿够了或者只差一件,则方案可行 
				plans++; 
			}
		}
		else if (sum == k) {
    
			plans++;
		} 
		return dp[x][y][sum][max + 1] = plans;// 这里sum不变,因为求的是(x,y)点的方案 
	}
	
	// 当前点不是出口,则有两种情况,向右走或者向下走(如果能走的话)
	// 而从当前点到出口的方案总数就是向右走和向下走两个方向的方案总数之和 
	if (x + 1 <= n) {
   // 向右走 
		// 决定了向右走,那么要看能不能拿当前点的宝物
		if (map[x][y] > max) {
   
			if (sum < k) {
   // 宝物不够,拿 
				plans += dfs(x + 1, y, sum + 1, map[x][y]);
				plans %= 1000000007;
			}
		} 
		plans += dfs(x + 1, y, sum, max);
		plans %= 1000000007;
		
	} 
	if (y + 1 <= m) {
   // 向下走 
		if (map[x][y] > max) {
   
			if (sum < k) {
   
				plans += dfs(x, y + 1, sum + 1, map[x][y]);
				plans %= 1000000007;
			} 
		} 
		plans += dfs(x, y + 1, sum, max);
		plans %= 1000000007;	
	}
	
	dp[x][y][sum][max + 1] = plans;
	return dp[x][y][sum][max + 1];
}

在这里插入图片描述

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

LL p;

LL qmul(LL a, LL b)
{
   
    LL res = 0;
    while (b)
    {
   
        if (b & 1) res = (res + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return res;
}

void mul(LL c[][2],LL a[][2],LL b[][2])  // c = a * b
{
   
    static LL t[2][2];
    memset(t,0,sizeof t);
    
    for(int i = 0;i < 2;i++)
        for(int j = 0;j < 2;j++)
            for(int k = 0;k < 2;k++)
            t[i][j
杭州电子科技大学在线评测系统(杭电OJ)中的题目1000-1100是一系列编程题,我将分别进行回答。 1000题是一个简单的入门题,要求计算两个整数的和。我们可以使用一个简单的算法,读取输入的两个整数,然后将它们相加,最后输出结果即可。 1001题是一个稍微复杂一些的题目,要求实现字符串的逆序输出。我们可以使用一个循环来逐个读取输入的字符,然后将这些字符存储在一个数组中。最后,我们可以倒序遍历数组并将字符依次输出,实现字符串的逆序输出。 1002题是一个求最大公约数的问题。我们可以使用辗转相除法来解决,即先求出两个数的余数,然后将被除数更新为除数,将除数更新为余数,直至两个数的余数为0。最后的被除数就是最大公约数。 1003题是一个比较简单的排序问题。我们可以使用冒泡排序算法来解决,即每次比较相邻的两个元素,如果它们的顺序错误就交换它们的位置。重复这个过程直至整个数组有序。 1100题是一个动态规划问题,要求计算给定序列中的最长上升子序列的长度。我们可以使用一个数组dp来保存到达每个位置的最长上升子序列的长度。每当遍历到一个位置时,我们可以将其和之前的位置比较,如果比之前位置的值大,则将其更新为之前位置的值加1,最后返回dp数组的最大值即可。 以上是对杭电OJ1000-1100题目的简要回答,涉及了一些基本的编程知识和算法思想。希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值