CSP---Week12 日常签到题(包含线性DP)

CSP-Week12 签到题

T1-水题

给出n个数,zjm想找出出现至少(n+1)/2次的数, 现在需要你帮忙找出这个数是多少?

INPUT和输入样例

本题包含多组数据:
每组数据包含两行。
第一行一个数字N(1<=N<=999999) ,保证N为奇数。
第二行为N个用空格隔开的整数。
数据以EOF结束。

输入样例:

5
1 3 2 3 3
11
1 1 1 1 1 5 5 5 5 5 5
7
1 1 1 1 1 1 1

Output和输出样例

对于每一组数据,你需要输出你找到的唯一的数。

输出样例:

3
5
1

解题思路

遍历一遍找出现最多次数的数字即可

T1源代码

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;

const int M=1e7;
int record[M];
int main()
{
    
    
	int group=0;
	int num=0;
	while(cin>>group)
	{
    
    
		int max_time=0;
		int max_num=0;
		memset(record,0,M);
		for(int i=0;i<group;i++)
		{
    
    
			scanf("%d",&num);
			record[num]++;
			if(record[num]>max_time)
			{
    
    
				max_time=record[num];
				max_num=num;
			}
		}
		printf("%d\n",max_num);
	}
	return 0;
 } 

T2-BFS板子

zjm被困在一个三维的空间中,现在要寻找最短路径逃生!
空间由立方体单位构成。
zjm每次向上下前后左右移动一个单位需要一分钟,且zjm不能对角线移动。
空间的四周封闭。zjm的目标是走到空间的出口。
是否存在逃出生天的可能性?如果存在,则需要多少时间?

INPUT和输入样例

输入第一行是一个数表示空间的数量。
每个空间的描述的第一行为L,R和C(皆不超过30)。
L表示空间的高度,R和C分别表示每层空间的行与列的大小。
随后L层,每层R行,每行C个字符。
每个字符表示空间的一个单元。’#‘表示不可通过单元,’.‘表示空白单元。
zjm的起始位置在’S’,出口为’E’。每层空间后都有一个空行。
L,R和C均为0时输入结束。

输入样例:

3 4 5
S….
.###.
.##..
###.#

#####
#####
##.##
##…

#####
#####
#.###
####E

1 3 3
S##
#E#
###

0 0 0

Output和输出样例

每个空间对应一行输出。
如果可以逃生,则输出如下
Escaped in x minute(s).
x为最短脱离时间。

如果无法逃生,则输出如下
Trapped!

输出样例:

Escaped in 11 minute(s).
Trapped!

解题思路

三维空间DFS,板子题。

T2源代码

#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;

const int M=35;
int flag[M][M][M];
int vis[M][M][M];
int L,R,C;

struct point
{
    
    
    int i;
    int j;
    int k;
};
point strart_p;
point end_p;
queue<point> q;
void clean_room()
{
    
    
    strart_p.i=0;
    strart_p.j=0;
    strart_p.k=0;
    for(int i=0;i<L;i++)
        for(int j=0;j<R;j++)
            for(int k=0;k<C;k++)
            {
    
    
                flag[i][j][k]=0;
                vis[i][j][k]=-1;
            }
}
char str[M];
void init()
{
    
    
    for(int i=0;i<L;i++)
    {
    
    
        for(int j=0;j<R;j++)
        {
    
    
        	scanf("%s",&str);
            for(int k=0;k<C;k++)
            {
    
    
                if(str[k]=='#')
                flag[i][j][k]=0;
                else if(str[k]=='.')
                flag[i][j][k]=1;
                else if(str[k]=='S')
                {
    
    
                    vis[i][j][k]=0;
                    strart_p.i=i;
                    strart_p.j=j;
                    strart_p.k=k;
                }
                else if(str[k]=='E')
                {
    
    
                    flag[i][j][k]=1;
                    end_p.i=i;
                    end_p.j=j;
                    end_p.k=k;
                }
            }
        }
        if(i!=L-1)
        getchar();
    }
}
point point_new;
void BFS()
{
    
    
    q.push(strart_p);
    while(!q.empty())
    {
    
    
        int i=q.front().i;
        int j=q.front().j;
        int k=q.front().k;
        q.pop();
        if(flag[i+1][j][k]==1 && vis[i+1][j][k]==-1 && i<L-1)
        {
    
    
            vis[i+1][j][k]=vis[i][j][k]+1;
            point_new.i=i+1;
            point_new.j=j;
            point_new.k=k;
            q.push(point_new);
        }
        if(flag[i-1][j][k]==1 && vis[i-1][j][k]==-1 && i>0)
        {
    
    
            vis[i-1][j][k]=vis[i][j][k]+1;
            point_new.i=i-1;
            point_new.j=j;
            point_new.k=k;
            q.push(point_new);
        }
        if(flag[i][j+1][k]==1 && vis[i][j+1][k]==-1 && j<R-1)
        {
    
    
            vis[i][j+1][k]=vis[i][j][k]+1;
            point_new.i=i;
            point_new.j=j+1;
            point_new.k=k;
            q.push(point_new);
        }
        if(flag[i][j-1][k]==1 && vis[i][j-1][k]==-1 && j>0)
        {
    
    
            vis[i][j-1][k]=vis[i][j][k]+1;
            point_new.i=i;
            point_new.j=j-1;
            point_new.k=k;
            q.push(point_new);
        }
        if(flag[i][j][k+1]==1 && vis[i][j][k+1]==-1 && k<C-1)
        {
    
    
            vis[i][j][k+1]=vis[i][j][k]+1;
            point_new.i=i;
            point_new.j=j;
            point_new.k=k+1;
            q.push(point_new);
        }
        if(flag[i][j][k-1]==1 && vis[i][j][k-1]==-1 && k>0)        
		{
    
    
            vis[i][j][k-1]=vis[i][j][k]+1;
            point_new.i=i;
            point_new.j=j;
            point_new.k=k-1;
            q.push(point_new);
        }
    }
}

int main()
{
    
    
	cin>>L>>R>>C;
    while(L!=0 || R!=0 || C!=0)
    {
    
    
        clean_room();
        getchar();
        init();
        BFS();
        if(vis[end_p.i][end_p.j][end_p.k]==-1)
        {
    
    
            printf("Trapped!\n");
        }
        else
        {
    
    
            printf("Escaped in %d minute(s).\n",vis[end_p.i][end_p.j][end_p.k]);
        }
        cin>>L>>R>>C;
    }
    return 0;
}

T3-线性DP

现在,我认为您已经在Ignatius.L的“最大和”问题中获得了AC。作为一个勇敢的ACMer,我们总是挑战自己,迎接更棘手的问题。现在,您面临着一个更困难的问题。

给定一个连续编号序列S 1,S 2,S 3,S 4内容S X,内容S Ñ(1≤X≤N≤1,000,000,-32768≤小号X ≤32767)。我们定义一个函数sum(i,j)= S i + … + S j(1≤i≤j≤n)。

现在给定一个整数m(m> 0),您的任务是查找m和i对和j对,它们使sum(i 1,j 1)+ sum(i 2,j 2)+总和(I 3,J 3)+ … + SUM(我中号,J 米)最大(I X ≤我ý ≤Ĵ X或I X ≤Ĵ ý ≤Ĵ X是不允许的)。

但是我很懒,我不想编写一个特殊的判断模块,所以您不必输出m对i和j,只需输出sum(i x,j x)(1 ≤x≤m)。

Input和输入样例

每个测试用例将以两个整数m和n开头,然后是n个整数S 1,S 2,S 3 … S n。
处理到文件末尾。
输入样例:

1 3 1 2 3
2 6 -1 4 -2 3 -2 3

Output和输出样例

一行输出上述最大和。

6
8

解题思路

题目来自HDU-1024,是一道经典的线性DP优化问题。

看到题目,可以想到的初步思路就是二维dp,dp[i][j]表示到第j个元素(选择第j个元素),选择了i段的最大值。a[j]表示输入的每个位置上的权值。

状态转移有下面两种情况:
1、选择该元素,且将该元素和前面的一段合并。该情况下的状态转移方程可以写成:
dp[i][j]=dp[i][j-1]+a[j]
2、选择该元素,且该元素单独存放。该情况下,dp[i][j]应为遍历所有选择i-1段中的最大值+a[j],状态转移方程可以写成:
dp[i][j]=max(dp[i-1][k](0<k<j))+a[j]
使用这种求解方式,可以解决小数据的问题。但是由于元素个数达到了1e6,O(n3)的算法显然无法解决问题,而且需要的空间太大,栈都可能会爆掉,需要找到其他的优化方式。

优化一:滚动数组减掉一个维度
关注两个状态转移方程,可以发现明显的特点:
dp[i][j]=dp[i][j-1]+a[j]
dp[i][j]=max(dp[i-1][k](0<k<j))+a[j]
所有 i 维的数据均通过 i-1 或者 i 维更新完成,这种情况下就可以使用背包问题中的滚动数组,一维即可解决。

优化二:使用数组存放前置已有的最优解来优化时间
使用了滚动数组,可以将空间复杂度优化到可行,但是随即而来的是TLE,时间性能仍然不够优秀。分析算法之后我们可以发现,主要计算集中在三个循环:
i 循环------更新选择的段数
j 循环------更新每个位置上的最大值
k 循环-----找到前 j-1 个位置上的最大值
突然我们发现一个问题,在跑 k重循环之前,这个最大值我们在上一个循环已经计算出来了啊!只不过当时我们没有记录他就被更新掉了。因此加上一个记录每个位置及其之前的最大值数组,通过维持最大值数组,就可以同时满足时间和空间复杂度的需求。

T3实现源代码

#include<iostream>
#include<stdio.h>
using namespace std;

const int M=1e6+5;
int dp[M];
int last_dp[M];
//dp[i][j]表示到J个为止选取j,i段的最大值
int a[M];
int m;
int n;
const int INF=-1e8;
int maxx=0;

int main()
{
    
    
    while(~scanf("%d %d",&m,&n))
    {
    
    
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        
        for(int i=0;i<=n;i++)
        {
    
    
            dp[i]=0;
            last_dp[i]=0;
        }


        for(int i=1;i<=m;i++)
        {
    
    
            maxx=INF;
            for(int j=i;j<=n;j++)
            {
    
    
                //两种情况:
                int ans1=dp[j-1]+a[j];
                int ans2=last_dp[j-1]+a[j];
                dp[j]=max(ans1,ans2);
                last_dp[j-1]=maxx;
                maxx=max(maxx,dp[j]);
            }
        }
        printf("%d\n",maxx);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43942251/article/details/106164712