uva 10599(dp)

本文探讨了如何使用机器人高效清理运动赛事后的场地垃圾,并详细介绍了路径优化算法以最大化垃圾清理数量,同时提供了多种可能的解决方案。通过分析地图网格中的垃圾分布,算法能够计算出最优的垃圾清理路径和清理方式,确保资源的最大利用。

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




Problem K

Robots(II)

Time Limit

1 Second

 

Your company provides robots that can be used to pick up litter from fields after sporting events and concerts. Before robots are assigned to a job, an aerial photograph of the field is marked with a grid. Each location in the grid that contains garbage is marked. All robots begin in the Northwest corner and end their movement in the Southeast corner. A robot can only move in two directions, either to the East or South. Upon entering a cell that contains garbage, the robot can be programmed to pick it up before proceeding. Once a robot reaches its destination at the Southeast corner it cannot be repositioned or reused. Since your expenses are directly proportional to the number of robots used for a particular job, you are interested in making the most out of them. Your task would be to use a robot to clean the maximum number of cells containing garbage. Now there can be many ways to do this job, so your task would be to report that number of ways and show us one such sample.

 

You see your robot can traverse many cells without picking up garbage, so for us a valid solution would be the sequence of cell numbers that the robot cleans. The robots only clean cells that contain garbage; but you can program them to avoid picking up garbage from specific cells, if you would want to.

 

 

 

 

 

 

 

 

 

 

In the figure above we show a field map that has 6 rows and 7 columns. The cells in a field map are numbered in row major order starting from 1. For the example shown here, the following 7 cells contain garbage: 2 (1,2), 4 (1,4), 11 (2, 4), 13 (2, 6), 25 (4, 4), 28 (4, 7) and 41 (6, 7). Here cells are presented in cell_number (row, column) format. Now the maximum number of cells that can be cleaned is 5, and there are 4 different ways to do that:

<2, 4, 11, 13, 28>

<2, 4, 11, 13, 41>

<2, 4, 11, 25, 28>

<2, 4, 11, 25, 41>

 

Input

An input file consists of one or more field maps followed by a line containing -1-1 to signal the end of the input data. The description of a field map starts with the number of rows and the number of columns in the grid. Then in the subsequent lines, the garbage locations follows. The end of a field map is signaled by 0 0. Each garbage location consists of two integers, the row and column, separated by a single space. The rows and columns are numbered as shown in Figure 1. The garbage locations will not be given in any specific order. And a location would not be reported twice for a field map. Please note that for all the test cases you are required to solve, the field map would be of at most 100 rows and 100 columns.

 

Output

The output for each test case starts with the serial number (starting from 1) for that test case. Then the following integers are listed on a line: N – the maximum number of cells that the robot can clean, C – the number of ways that these N cells can be cleaned, and N numbers describing one possible sequence of cell numbers that the robot will clean. As there can be C different such sequences and we are asking for only one sequence any valid sequence would do. Make sure that all these 2+N integers for a test case are printed on a single line. There must be one space separating two consecutive integers and a space between the colon and the first integer on the line. See the sample output format for a clear idea.

 

 

Sample Input

Output for Sample Input

6 7

1 2

1 4

2 4

2 6

4 4

4 7

6 6

0 0

4 4

1 1

2 2

3 3

4 4

0 0

-1 -1

CASE#1: 5 4 2 4 11 13 28

CASE#2: 4 1 1 6 11 16

 

Problemsetter: Monirul Hasan (The background story and images are from the "ACM Mid-Central Regional Programming Contest, 2003")

Member of Elite Problemsetters' Panel


难点在路径数不是根据走的路径不同计数,而是根据走过的垃圾点不同计数。dp[i][j][k]表示从左上角走到i,j 取到k个垃圾的方案数。dpl[i][j][k]表示从左上角走到i,j必须经过i行上的某个垃圾点,得到k个垃圾的方案数。这样计数就不会记重了。看了下别人的题解,发现是用lis求得,有意思。
#include<cstdio>
#include<map>
#include<queue>
#include<cstring>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 100 + 5;
const int INF = 1000000000;
typedef long long LL;
typedef pair<int, int> P;

int maze[maxn][maxn];
int dp[maxn][maxn][2*maxn], dpl[maxn][maxn][2*maxn];

struct Node{
    int x, y, cnt;
    Node(){}
    Node(int x, int y, int cnt){
        this -> x = x;
        this -> y = y;
        this -> cnt = cnt;
    }
};
Node trace[maxn][maxn][2*maxn];
vector<int> ans;

int main(){
    int kase = 0;
    int n, m;
    while(scanf("%d%d", &n, &m)){
        kase++;
        if(n == -1 && m == -1)
            break;
        memset(maze, 0, sizeof maze);
        int x, y;
        while(scanf("%d%d", &x, &y)){
            if(x == 0 && y == 0)
                break;
            maze[x][y] = 1;
        }
        memset(dp, 0, sizeof dp);
        memset(dpl, 0, sizeof dpl);
        if(maze[1][1]==1)
            dp[1][1][1] = dpl[1][1][1] = 1;
        else
            dp[1][1][0] = dpl[1][1][0] = 1;
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= m;j++){
                if(i == 1 && j == 1)
                    continue;
                for(int k = 0;k <= n+m-1;k++){
                    if(maze[i][j] == 1 && k != 0){
                        if(i > 1 && dp[i-1][j][k-1] > 0){
                            dp[i][j][k] = dp[i-1][j][k-1];
                            trace[i][j][k] = Node(i-1, j, k-1);
                        }
                        if(j > 1 && dpl[i][j-1][k-1] > 0){
                            dp[i][j][k] += dpl[i][j-1][k-1];
                            trace[i][j][k] = Node(i, j-1, k-1);
                        }
                        dpl[i][j][k] = dp[i][j][k];
                    }
                    else{
                        if(i > 1 && dp[i-1][j][k] > 0){
                            dp[i][j][k] = dp[i-1][j][k];
                            trace[i][j][k] = Node(i-1, j, k);
                        }
                        if(j > 1 && dpl[i][j-1][k] > 0){
                            dp[i][j][k] += dpl[i][j-1][k];
                            trace[i][j][k] = Node(i, j-1, k);
                        }
                        if(j > 1)
                            dpl[i][j][k] = dpl[i][j-1][k];

                    }
                }
            }
        }

        int Max, cnt;
        for(int i = n+m-1;i >= 0;i--){
            if(dp[n][m][i] != 0){
                Max = i;
                cnt = dp[n][m][i];
                break;
            }
        }
        printf("CASE#%d: %d %d", kase, Max, cnt);

        int px = n, py = m;
        ans.clear();
        while(1){
            if(maze[px][py] == 1)
                ans.push_back(m*(px-1)+py);
            if(px == 1 && py == 1)
                break;
            Node& tem = trace[px][py][Max];
            px = tem.x;
            py = tem.y;
            Max = tem.cnt;
        }
        reverse(ans.begin(), ans.end());
        for(int i = 0;i < ans.size();i++){
            printf(" %d", ans[i]);
        }
        printf("\n");
    }
    return 0;
}



### 关于UVa 307问题的动态规划解法 对于UVa 307 (Sticks),虽然通常采用深度优先搜索(DFS)+剪枝的方法来解决这个问题,但也可以尝试构建一种基于动态规划的思想去处理它。然而,在原描述中并未提及具体的动态规划解决方案[^3]。 #### 动态规划解题思路 考虑到本题的核心在于通过若干根木棍拼接成更少数量的新木棍,并使得这些新木棍尽可能接近给定的目标长度。为了应用动态规划技术,可以定义一个二维数组`dp[i][j]`表示从前i种不同类型的木棍中选取一些组合起来能否恰好组成总长度为j的情况: - 如果存在这样的组合,则`dp[i][j]=true`; - 否则`dp[i][j]=false`. 初始化时设置`dp[0][0]=true`, 表明没有任何木棍的情况下能够构成零长度。接着遍历每种类型的木棍以及所有可能达到的累积长度,更新对应的布尔值。最终检查是否存在某个k使得`sum/k * k == sum && dp[n][sum/k]`成立即可判断是否能成功分割。 这种转换方式利用了动态规划中的两个重要特性:最优化原理和重叠子问题属性。具体来说,每当考虑一根新的木棍加入现有集合时,只需要关注之前已经计算过的较短长度的结果,从而避免重复运算并提高效率[^1]. #### Python代码实现 下面给出一段Python伪代码用于说明上述逻辑: ```python def can_partition_sticks(stick_lengths, target_length): n = len(stick_lengths) # Initialize DP table with False values. dp = [[False]*(target_length + 1) for _ in range(n + 1)] # Base case initialization. dp[0][0] = True for i in range(1, n + 1): current_stick = stick_lengths[i - 1] for j in range(target_length + 1): if j >= current_stick: dp[i][j] |= dp[i - 1][j - current_stick] dp[i][j] |= dp[i - 1][j] return any(dp[-1][l] and l != 0 for l in range(target_length + 1)) # Example usage of the function defined above. stick_lengths_example = [...] # Input your data here as a list. total_sum = sum(stick_lengths_example) if total_sum % min(stick_lengths_example) == 0: result = can_partition_sticks(stick_lengths_example, int(total_sum / min(stick_lengths_example))) else: result = False print('Can partition sticks:', 'Yes' if result else 'No') ``` 需要注意的是,这段代码只是一个简化版本,实际比赛中还需要进一步调整参数以适应特定输入范围的要求。此外,由于题目本身允许有多余的小段剩余未被使用,所以在设计状态转移方程时也应适当放宽条件.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值