Working out(详解)

本文介绍了一种基于矩阵的最优路径规划算法,通过四个方向的动态规划寻找两组人员在矩阵中相遇并最大化总收益的方法。文章详细解释了算法原理,并提供了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the beach. The gym where they go is a matrix a with n lines and mcolumns. Let number a[i][j] represents the calories burned by performing workout at the cell of gym in the i-th line and the j-th column.

Iahub starts with workout located at line 1 and column 1. He needs to finish with workout a[n][m]. After finishing workout a[i][j], he can go to workout a[i + 1][j] ora[i][j + 1]. Similarly, Iahubina starts with workout a[n][1] and she needs to finish with workout a[1][m]. After finishing workout from cell a[i][j], she goes to eithera[i][j + 1] or a[i - 1][j].

There is one additional condition for their training. They have to meet in exactly one cell of gym. At that cell, none of them will work out. They will talk about fast exponentiation (pretty odd small talk) and then both of them will move to the next workout.

If a workout was done by either Iahub or Iahubina, it counts as total gain. Please plan a workout for Iahub and Iahubina such as total gain to be as big as possible. Note, that Iahub and Iahubina can perform workouts with different speed, so the number of cells that they use to reach meet cell may differs.

Input

The first line of the input contains two integers n and m (3 ≤ n, m ≤ 1000). Each of the next n lines contains m integers: j-th number from i-th line denotes elementa[i][j] (0 ≤ a[i][j] ≤ 105).

Output

The output contains a single number — the maximum total gain possible.

Example
Input
3 3
100 100 100
100 1 100
100 100 100
Output
800
Note

Iahub will choose exercises a[1][1] → a[1][2] → a[2][2] → a[3][2] → a[3][3]. Iahubina will choose exercises a[3][1] → a[2][1] → a[2][2] → a[2][3] → a[1][3].


题解:

Orz,看到这题的时候已经懵逼了,然后搜题解,问同学,一气呵成……

(每次遇到不会的感觉好难的题,一搜题解,大佬们都说是水题……忧伤,嘤嘤嘤qwq)

分析:

设4个数组从4个角分别搜索dp1到dp4

dp1[i][j]表示的是从(1,1)到(i,j)的最大值

我看别人题解是一共有3个疑问:

1.为什么从4个角搜索:

假设a,b相遇点为点A(i,j)那么题中所求的最大值为,左上到A,A到右下,左下到A,A到右上

dp1[i][j]仅仅是(1,1)到A点的最大值,也需要求dp4[i][j](右下到A的最大距离),相应的也要求dp2[i][j],dp3[i][j]

2.为什么代码结尾的两个for循环不考虑4个边界:

由题知,a,b的所走的路径画出来只能有一个交点,也就是交点1个,且a不能走b走过的路,b也不能走a走过的路

若在边界相遇:eg:

在(3,1),则a的上一个位置时(2,1),b是(4,1),a的下一个位置是(3,2)或(4,1),b的下一位置是(3,2)或(2,1)

不符合所以不考虑边界。

3.代码后部ans讨论时,每枚举一个交点,为什么只有两种情况

见图(图是盗滴)


所以这有两种情况

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp1[1003][1003],dp2[1003][1003],dp3[1003][1003],dp4[1003][1003];
int a[1003][1003];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
        }
    }
    memset(dp1,0,sizeof(dp1));
    memset(dp2,0,sizeof(dp2));
    memset(dp3,0,sizeof(dp3));
    memset(dp4,0,sizeof(dp4));

    for(int i=1;i<=n;i++){//左上
        for(int j=1;j<=m;j++){
            dp1[i][j]=max(dp1[i][j-1],dp1[i-1][j])+a[i][j];
        }
    }

    for(int i=n;i>=1;i--){//左下
        for(int j=1;j<=m;j++){
            dp2[i][j]=max(dp2[i+1][j],dp2[i][j-1])+a[i][j];
        }
    }
    for(int i=1;i<=n;i++){//右上
        for(int j=m;j>=1;j--){
            dp3[i][j]=max(dp3[i][j+1],dp3[i-1][j])+a[i][j];
        }
    }
    for(int i=n;i>=1;i--){//右下
        for(int j=m;j>=1;j--){
            dp4[i][j]=max(dp4[i+1][j],dp4[i][j+1])+a[i][j];
        }
    }


    int ans=0;
    for(int i=2;i<n;i++){
        for(int j=2;j<m;j++){
            ans=max(ans,dp1[i][j-1]+dp4[i][j+1]+dp3[i-1][j]+dp2[i+1][j]);
            ans=max(ans,dp1[i-1][j]+dp4[i+1][j]+dp3[i][j+1]+dp2[i][j-1]);
        }
    }
    printf("%d\n",ans);
}

### Java 并发包 (JUC) 的详细介绍与使用方法 #### 什么是 JUC? Java 并发包(`java.util.concurrent`, 简称 JUC)是 JDK 提供的一套用于支持多线程并发编程的工具集。它不仅简化了开发人员编写复杂并发程序的工作,还提供了许多高级功能来优化性能和安全性。 --- #### 主要组成部分及其详解 ##### 1. **原子变量** 原子变量通过硬件级别的 CAS(Compare And Swap)机制实现了无锁化的高效操作[^2]。以下是常见的原子类: - `AtomicInteger`: 支持整型的原子更新。 - `AtomicLong`: 支持长整型的原子更新。 - `AtomicReference<T>`: 支持对象类型的原子更新。 示例代码如下: ```java import java.util.concurrent.atomic.AtomicInteger; public class AtomicExample { private static AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args) { for(int i=0;i<1000;i++) { new Thread(() -> { int value = counter.incrementAndGet(); System.out.println(Thread.currentThread().getName() + ": " + value); }).start(); } } } ``` --- ##### 2. **线程池** 线程池的核心类是 `ThreadPoolExecutor`,其设计目标是在高负载下减少全局锁的影响并提高吞吐量[^3]。创建线程的方式主要包括继承 `Thread` 类、实现 `Runnable` 接口以及实现带有返回值的 `Callable` 接口。 推荐使用的工厂模式来自 `Executors` 工具类,例如固定大小线程池: ```java import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(5); for(int i=0;i<10;i++) { final int taskNumber = i; executor.submit(() -> { System.out.println("Task "+taskNumber+" executed by "+Thread.currentThread().getName()); }); } executor.shutdown(); } } ``` --- ##### 3. **同步工具** JUC 中提供了一些高级同步工具,帮助开发者解决复杂的线程协作问题: ###### a. **CountDownLatch** `CountDownLatch` 可以让一个或多个线程等待其他线程完成某些操作后再继续执行[^5]。 ```java import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); for(int i=0;i<3;i++) { new Thread(() -> { try { System.out.println(Thread.currentThread().getName()+" is working..."); Thread.sleep((long)(Math.random()*1000)); } catch (InterruptedException e) {} latch.countDown(); }).start(); } latch.await(); System.out.println("All tasks are done."); } } ``` ###### b. **CyclicBarrier** 类似于 `CountDownLatch`,但它可以重复使用。 ```java import java.util.concurrent.BARRIER; public class CyclicBarrierExample { BARRIER barrier = new BARRIER(3, () -> System.out.println("All parties reached the barrier.")); public void testBarrier() { for(int i=0;i<3;i++) { new Thread(() -> { try { System.out.println(Thread.currentThread().getName()+": Waiting at barrier"); barrier.await(); } catch(Exception ex) {} System.out.println(Thread.currentThread().getName()+": Continuing work after barrier"); }).start(); } } } ``` ###### c. **Semaphore** `Semaphore` 控制同时访问某一资源的最大线程数。 ```java import java.util.concurrent.Semaphore; public class SemaphoreExample { private Semaphore semaphore = new Semaphore(3); public void accessResource() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName()+" accessing resource..."); Thread.sleep(1000); } catch (Exception e) {} finally { semaphore.release(); } } } ``` --- ##### 4. **锁机制** 除了传统的 `synchronized` 关键字外,JUC 还引入了更加灵活的锁&mdash;&mdash;`ReentrantLock` 和条件队列 `Condition`[^4]。 示例代码展示如何使用显式锁: ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockExample { private final Lock lock = new ReentrantLock(); public void criticalSection() { lock.lock(); try { // Critical section code here... System.out.println(Thread.currentThread().getName()+" entered critical section."); } finally { lock.unlock(); } } } ``` --- ##### 5. **Fork/Join 框架** 适用于大规模数据处理场景中的分治算法[^1]。 ```java import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; class SumTask extends RecursiveTask<Integer> { private final int[] array; private final int start; private final int end; public SumTask(int[] array, int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { if(end - start <= 10){ int sum = 0; for(int i=start;i<=end;i++) sum += array[i]; return sum; }else{ int mid = (start + end)/2; SumTask leftTask = new SumTask(array,start,mid); SumTask rightTask = new SumTask(array,mid+1,end); invokeAll(leftTask,rightTask); return leftTask.join() + rightTask.join(); } } } public class ForkJoinExample { public static void main(String[] args) { int[] data = new int[100]; // Initialize with values ForkJoinPool pool = new ForkJoinPool(); int result = pool.invoke(new SumTask(data,0,data.length-1)); System.out.println(result); } } ``` --- #### 最佳实践建议 1. 尽可能复用线程而不是频繁创建销毁它们。 2. 避免长时间持有锁以防死锁发生。 3. 对共享状态的操作优先考虑不可变性或者借助原子变量代替手动加锁。 4. 调试并发程序时注意观察竞争条件、内存可见性和活锁等问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值