# 充实的寒假生活 (GREEDY/DP)

描述

寒假马上就要到了,龙傲天同学获得了从第 0 天开始到第 60 天结束为期 61 天超长寒假,他想要尽可能丰富自己的寒假生活。
现提供若干个活动的起止时间,请计算龙同学这个寒假至多可以参加多少个活动?注意所参加的活动不能有任何时间上的重叠,在第 x 天结束的活动和在第 x 天开始的活动不可同时选择。

输入

第一行为整数 n,代表接下来输入的活动个数 (n < 10000)
紧接着的 n 行,每一行都有两个整数,第一个整数代表活动的开始时间,第二个整数代表全结束时间

输出

输出至多参加的活动个数

样例输入

5
0 0
1 1
2 2
3 3
4 4

样例输出

5

解决

class Solution(object):
    def eraseOverlapIntervals(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: int
        """
        if not intervals or len(intervals) == 0:
            return 0
        intervals.sort(key = lambda x: x[0])  # 按左端点从小到大排序
        temp_pos = 0
        cnt = 0
        for i in range(1, len(intervals)):
            if intervals[temp_pos][1] >= intervals[i][0]:  # 当当前区间右端点 > i 区间左端点
                if intervals[i][1] < intervals[temp_pos][1]:  # 当 i 区间右端点 & lt; 当前区间右端点,表示 i 区间被覆盖在当前区间中
                    temp_pos = i  # 更新 temp_pos,选择覆盖范围小的 i 区间
                cnt += 1  # 当前区间右端点 > i 区间左端点都要计数 + 1
            else:
                temp_pos = i  # 当当前区间右端点 & lt;=i 区间左端点,表示不重叠,要更新 temp_pos
        return len(intervals)-cnt
if __name__ == "__main__":
    n=int(input())
    intervals=[]
    for i in range(n):
        intervals.append(list(map(int, input().split())))
    print(Solution().eraseOverlapIntervals(intervals))

# 和为给定数

描述

给出若干个整数,询问其中是否有一对数的和等于给定的数。

输入

共三行:
第一行是整数 n (0 < n <= 100,000),表示有 n 个整数。
第二行是 n 个整数。整数的范围是在 0 到 108 之间。
第三行是一个整数 m(0 <= m <= 230),表示需要得到的和。

输出

若存在和为 m 的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行 No。

样例输入

4
2 5 1 4
6

样例输出

1 5

解决

def find(key,base,top): #二分查找
    while base<=top:
        mid = (base+top)//2
        if a[mid]==key:
            return True
        elif a[mid]<key: 
            base=mid+1
        else: 
            top=mid-1
    return False 
n=int(input())
a=list(map(int,input().split()))
a=sorted(a)
flag=0
# print(a)
m=int(input())
for i in range(n):
    key=m-a[i]
    base=i+1
    top=n-1
    if find(key,base,top):
        print(a[i],key)
        flag=1
        break
if flag==0:
    print("No")

# 求逆序对数

描述

对于一个长度为 N 的整数序列 A ,满足 i < j 且  Ai > Aj . 的数对 (i,j) 称为整数序列 A 的一个逆序
请求出整数序列 A 的所有逆序对个数

输入

输入包含多组测试数据,每组测试数据有两行
第一行为整数 N(1 <= N <= 20000) ,当输入 0 时结束
第二行为 N 个整数,表示长为 N 的整数序列

输出

每组数据对应一行,输出逆序对的个数

样例输入

5
1 2 3 4 5
5
5 4 3 2 1
1
1
0

样例输出

0
10
0

解决 1

冒泡,可能会超时

def main():
    while True:
        n = int(input())
        if n==0:
            return
        ll = list(map(int, input().split()))
        # print(ll)
        c=[0 for i in range(101)]
        group=0
        for i in range(n-1):
            for j in range(i,n-1):
                if ll[j]>ll[j+1]:
                    group+=1
        print(group)
if __name__ == '__main__':
    main()

解决 2

归并

def merge_sort(a):
    s = 0
    if len(a) <= 1: return 0
    mid = len(a) // 2
    l = a[:mid]
    r = a[mid:]
    s += merge_sort(l) + merge_sort(r)
    i = j = k = 0
    while (i < len(l) and j < len(r)):
        if (l[i] <= r[j]):
            a[k] = l[i]
            i += 1
            k += 1
        else:
            a[k] = r[j]
            j += 1
            k += 1
            s += len(l) - i
    while (i < len(l)):
        a[k] = l[i]
        i += 1
        k += 1
    while (j < len(r)):
        a[k] = r[j]
        j += 1
        k += 1
    return s
def main():
    while True:
        n = int(input())
        if n==0:
            return
        ll = list(map(int, input().split()))
        print(merge_sort(ll))
if __name__ == '__main__':
    main()

# 小木棍

描述

小明将一批等长的木棍随机切成最长为 50 单位的小段。现在他想要将木棍还原成原来的状态,但是却忘记了原来的木棍数量和长度。请写一个程序帮助他计算如果还原成原来的等长木棍,其长度可能的最小值。所有的长度均大于 0。

输入

输入包含多个实例。每个实例有两行,第一行是切割后的木棍数量 n(最多 64 个),第二行为 n 个以空格分开的整数,分别为每根木棍的长度。输入的最后以 n 为 0 结束。

输出

对于每个实例,输出一行其长度的可能的最小值。

样例输入

9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0

样例输出

6
5

来源

来自计算概论 B 期末考试,本题对数据进行了弱化

解决

N=105
a=[0 for _ in range(N)]
v=[0 for _ in range(N)]
target=0
n=0
maxn=0
def dfs(cnt, len, pos):
    if cnt == target:
        return True #拼够了根数,符合题意
    if len == maxn:
        return dfs(cnt+1, 0, 0) #拼完了一根 继续下一根
    i = pos
    while i<n:
        if v[i]==0 and len+a[i]<=maxn:
            v[i]=1
            if dfs(cnt, len+a[i], i):
                return True
            v[i]=0
            if len == 0:
                return False #凑第一根的时候可以随便选,如果随便选都凑不成一根,那这个长度不行 神奇剪枝!!
            while i+1<n and a[i+1]==a[i]:
                i += 1 #如果用当前的小木段拼凑 失败则与它等长的同样失败,小剪枝
        i += 1
    return False
while True:
    n=int(input())
    if n==0:
        break
    arr = input()
    a = [0 for _ in range(N)]
    a = [int(n) for n in arr.split()]
    asum = 0
    asum = sum(a)
    a=sorted(a,reverse=True)
    maxn = 0
    maxn=a[0]
    while maxn <= asum:
        if asum%maxn == 0:
            target = asum / maxn
            v = [0 for _ in range(N)]
            if dfs(0, 0, 0):
                break
        maxn += 1
    print(maxn)

# 修仙之路

描述

修仙之路长漫漫,逆水行舟,不进则退!你过五关斩六将,终于来到了仙界。仙界是一个 r 行 c 列的二维格子空间,每个单元格是一个” 境界 “,每个境界都有等级。你需要任意选择其中一个境界作为起点,从一个境界可以前往上下左右相邻四个境界之一 ,当且仅当新到达的境界等级增加。你苦苦行走,直到所在的境界等级比相邻四个境界的等级都要高为止,一览众山小。请问包括起始境界在内最长修仙路径需要经过的境界数是多少?

输入

第一行为两个正整数,分别为 r 和 c(1<=r,c<=100)。
接下来有 r 行,每行有 c 个 0 到 100000000 之间的整数,代表各境界的等级。

输出

输出一行,为最长修仙路径需要经过的境界数(包括起始境界)。

样例输入

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9

样例输出

25

解决 1

没有考虑位于边界的 “仙境”

import java.util.Scanner;
/**]
 *
 * 5 5
 * 1 2 3 4 5
 * 16 17 18 19 6
 * 15 24 25 20 7
 * 14 23 22 21 8
 * 13 12 11 10 9
 *
 *
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc =new Scanner(System.in);
        int m= sc.nextInt();
        int n =sc.nextInt();
        int [][] nums = new int[m][n];
        for(int i=0;i<m;i++){
            for(int j = 0;j<n;j++){
                nums[i][j] = sc.nextInt();
            }
        }
       /* int [][] dp = new int[m][n];
        dp[0][0] =1;
         int target =0;
        // i+1,j // i-1,j // i,j+1// i,j-1
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(i==0&&j==0){
                    continue;
                }
                if(i+1<m&&j<n && nums[i+1][j]<nums[i][j]){
                    dp [i][j] =Math.max(dp[i+1][j],dp[i][j])+1;
                }
                if (0<=i-1&&j<n&& nums[i-1][j]<nums[i][j]){
                    dp [i][j] =Math.max(dp[i-1][j],dp[i][j])+1;
                }
                 if(i<m&&j+1<n && nums[i][j+1]<nums[i][j]){
                    dp [i][j] =Math.max(dp[i][j+1],dp[i][j])+1;
                }
                if(i<m&&j-1>=0 && nums[i][j-1]<nums[i][j]){
                    dp [i][j] =Math.max(dp[i][j-1],dp[i][j])+1;
                }
                int tmp = nums[i][j];
                int tmp1 = dp[i][j];
                target = Math.max(dp[i][j],target);
            }
        }
        System.out.println(target);
*/
      int a = dfs(nums,0,0,m,n,1);
        System.out.println(a);
    }
    public static int  dfs(int [][] nums ,int i,int j ,int m, int n ,int tt ){
        if(i<0 || i>m || j<0||j>n){
            return 0;
        }
        if(is(nums,i,j,m,n)==4){
           return tt;
        }
        int a =0;
        int b=0;
        int c=0;
        int d=0;
        if(i-1>=0&&nums[i][j]<nums[i-1][j]){
            a= dfs(nums, i-1, j, m, n,tt+1);
        }
         if(i+1<m&&nums[i][j]<nums[i+1][j]){
            b= dfs(nums, i+1, j, m, n,tt+1);
        }
         if(j-1>=0&&nums[i][j]<nums[i][j-1]){
            c= dfs(nums, i, j-1, m, n,tt+1);
        }
         if(j+1<n&&nums[i][j]<nums[i][j+1]){
            d= dfs(nums, i, j+1, m, n,tt+1);
        }
         a= Math.max(a,b);
         a= Math.max(a,c);
         a= Math.max(a,d);
        return  a;
    }
    public static int is(int [][] nums,int i,int j,int m,int n){
        int tar=0;
        if(i-1>=0){
            if( nums[i][j]>nums[i-1][j]){
               tar++;
            }
        }
        if(i+1<m){
            if( nums[i][j]>nums[i+1][j]){
                tar++;
            }
        }
        if(j-1>=0){
            if( nums[i][j]>nums[i][j-1]){
                tar++;
            }
        }
        if(j+1<n){
            if( nums[i][j]>nums[i][j+1]){
                tar++;
            }
        }
        return  tar;
    }
}

来自啊鱼咕嘟

解决 2

# 5 5
# 1 2 3 4 5
# 16 17 18 19 6
# 15 24 25 20 7
# 14 23 22 21 8
# 13 12 11 10 9
n,m=map(int,input().split())
nums = []
for _ in range(n):
	nums.append(list(map(int, input().split())))
dp=[[-1]* m for _ in range(n)]
move=[[0,1],[1,0],[-1,0],[0,-1]]
def dfs(i,j):
    if dp[i][j]!=-1:
        return dp[i][j]
    ret=1
    for oi,oj in move:
        ni,nj=i+oi,j+oj
        if 0<=ni<n and 0<=nj<m and nums[i][j]>nums[ni][nj]:
            ret=max(ret,dfs(ni,nj)+1)
    dp[i][j]=ret
    return dp[i][j]
res=0
for i in range(n):
    for j in range(m):
        res=max(res,dfs(i,j))
print(res)

# 拦截导弹

描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于 30000 的正整数),计算这套系统最多能拦截多少导弹。

输入

第一行是一个整数 N(不超过 15),表示导弹数。
第二行包含 N 个整数,为导弹依次飞来的高度(雷达给出的高度数据是不大于 30000 的正整数)。

输出

一个整数,表示最多能拦截的导弹数。

样例输入

8
389 207 155 300 299 170 158 65

样例输出

6

解决

i=0
data = [0 for _ in range(100)]
ans = [0 for _ in range(100)]
n=int(input())
arr=input()
data = [int(n) for n in arr.split()]
ans[0] = 1
maxt = 1
for j in range(1, n):
    ans[j] = 1
    for i in range(0, j):
        if data[i]>=data[j]:
            if ans[i]+1> ans[j]:
                ans[j] = ans[i]+1
    if ans[j]> maxt:
        maxt = ans[j]
print(maxt)

# 采药(DP)

描述

辰辰是个很有潜能、天资聪颖的孩子,他的梦想是称为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入

输入的第一行有两个整数 T(1 <= T <= 1000)和 M(1 <= M <= 100),T 代表总共能够用来采药的时间,M 代表山洞里的草药的数目。接下来的 M 行每行包括两个在 1 到 100 之间(包括 1 和 100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出

输出只包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例输入

70 3
71 100
69 1
1 2

样例输出

3

来源

NOIP 2005

解决

N=1010
T,M=map(int,input().split())
f = [0 for _ in range(N)]
for i in range(0, M):
        v,w=map(int,input().split())
        for j in range(T, v - 1, -1):
            f[j] = max(f[j], f[j - v] + w)
print(f[T])

# 简单的整数划分问题

描述

将正整数 n 表示成一系列正整数之和,n=n1+n2+…+nk, 其中 n1>=n2>=…>=nk>=1 ,k>=1 。
正整数 n 的这种表示称为正整数 n 的划分。正整数 n 的不同的划分个数称为正整数 n 的划分数。

输入

标准的输入包含若干组测试数据。每组测试数据是一个整数 N (0 < N <= 50)。

输出

对于每组测试数据,输出 N 的划分数。

样例输入

5

样例输出

7

提示

5, 4+1, 3+2, 3+1+1, 2+2+1, 2+1+1+1, 1+1+1+1+1

解决

def f(x,y):
        if y == 1:
            return 1
        elif y <= 0:
            return 0
        elif x < y:
            return 0
        else:
            return(f(x - 1,y - 1) + f(x - y,y))
while True:
    try:
        n = int(input())
        s = 1
        for i in range(n):
            s = s + f(n,i)
        print(s)
    except EOFError: break
更新於 閱讀次數

請我喝[茶]~( ̄▽ ̄)~*

fygod 微信支付

微信支付

fygod 支付寶

支付寶

fygod PayPal

PayPal