4.18

本文探讨了如何通过动态规划解决两类典型问题:寻找送餐员在直线上送达食物的最优路径,以及将两个字符串转换为相同内容所需的最小操作次数。文章详细解析了状态转移方程的设计与实现,为读者提供了深入理解区间DP算法的实例。

1
When we are focusing on solving problems, we usually prefer to stay in front of computers rather than go out for lunch. At this time, we may call for food delivery.

Suppose there are N people living in a straight street that is just lies on an X-coordinate axis. The ith person's coordinate is Xi meters. And in the street there is a take-out restaurant which has coordinates X meters. One day at lunchtime, each person takes an order from the restaurant at the same time. As a worker in the restaurant, you need to start from the restaurant, send food to the N people, and then come back to the restaurant. Your speed is V-1 meters per minute.

You know that the N people have different personal characters; therefore they have different feeling on the time their food arrives. Their feelings are measured by Displeasure Index. At the beginning, the Displeasure Index for each person is 0. When waiting for the food, the ith person will gain Bi Displeasure Index per minute.

If one's Displeasure Index goes too high, he will not buy your food any more. So you need to keep the sum of all people's Displeasure Index as low as possible in order to maximize your income. Your task is to find the minimal sum of Displeasure Index.

Input

The input contains multiple test cases, separated with a blank line. Each case is started with three integers N ( 1 <= N <= 1000 ), V ( V > 0), X ( X >= 0 ), then N lines followed. Each line contains two integers Xi ( Xi >= 0 ), Bi ( Bi >= 0), which are described above.

You can safely assume that all numbers in the input and output will be less than 231 - 1.

Please process to the end-of-file.

Output

For each test case please output a single number, which is the minimal sum of Displeasure Index. One test case per line.

Sample Input

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

Sample Output

55
这题就是求一个最短时间,每一步的最优怎么选择,刚开始想这题是没啥思路的,每一步的情况就要用i到j来表示,然后[i][j][0]表示在左边,[i][j][1]表示在右边。那每一步该咋选择呢,每一步就是看是要向左走还是向右走,选择的标准是什么,这个是真的难想,本来会想这一步怎么用的时间最短但是这样选的是毫无意义的啊,所以就,,最后得出的结论就是每步尽量让外面的人不满意度增加的最少,需要注意的就是外面的不满意度要包括目的地的。增加的不满意度就是(地点1-地点2)*(sum[n]-(sum[j]-sum[i]))刚开始也不必考虑速度,最后相乘就行了。
就可以得到状态转移方程:
dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(t[i+1].num-t[i].num)*(sum[n]-sum[j]+sum[i]));
 dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(t[i].num-t[i].num)*(sum[n]-sum[j]+sum[i]));
 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(t[j].num-t[i].num)*(sum[n]-sum[j-1]+sum[i-1]));
 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(t[j].num-t[j-1].num)*(sum[n]-sum[j-1]+sum[i-1]));

              
  整个解题的过程还是挺难的,状态转移方程也写的很晕,最后看了别人的代码才写清楚  

 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<iomanip>
using namespace std;
const int INF=0x3f3f3f3f;
struct peo{
    int num;
    int un;
}t[1005];

long int sum[1005];
int v,n,st;
int dp[1005][1005][2];
bool flag=false;
int min(int a,int b)
{``
    return a>b?b:a;
}
bool cmp(peo a,peo b)
{
    return a.num<b.num;
}
int main(){
    cin>>n>>v>>st;
    int i,j,k;
    memset(sum,0,sizeof(sum));
    for(i=1;i<=n;i++)
    {
        cin>>t[i].num>>t[i].un;
    } 
    sort(t+1,t+1+n,cmp);
    sum[1]=t[1].num;
    for(i=2;i<=n;i++)
        sum[i]=sum[i-1]+t[i].un;

    for(i=1;i<=n;i++)
        dp[i][i][0]=dp[i][i][1]=abs(t[i].num-st)*sum[n];
    for(int l=1;l<n;l++)
    for(i=1;i<=n;i++)
    {
    
        j=i+l;
 dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][0]+(t[i+1].num-t[i].num)*(sum[n]-sum[j]+sum[i]));
 dp[i][j][0]=min(dp[i][j][0],dp[i+1][j][1]+(t[i].num-t[i].num)*(sum[n]-sum[j]+sum[i]));
 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][0]+(t[j].num-t[i].num)*(sum[n]-sum[j-1]+sum[i-1]));
 dp[i][j][1]=min(dp[i][j][1],dp[i][j-1][1]+(t[j].num-t[j-1].num)*(sum[n]-sum[j-1]+sum[i-1]));

    }

    k=min(dp[1][n][0],dp[1][n][1]);
    cout<<k*v<<endl;
    }
 

 

 2

Problem Description
There are two strings A and B with equal length. Both strings are made up of lower case letters. Now you have a powerful string painter. With the help of the painter, you can change a segment of characters of a string to any other character you want. That is, after using the painter, the segment is made up of only one kind of character. Now your task is to change A to B using string painter. What’s the minimum number of operations?
 

Input
Input contains multiple cases. Each case consists of two lines:
The first line contains string A.
The second line contains string B.
The length of both strings will not be greater than 100.
 

Output
A single line contains one integer representing the answer.
 

Sample Input
zzzzzfzzzzz abcdefedcba abababababab cdcdcdcdcdcd
 

Sample Output
6 7

这题题意好难理解。。看明白了就是经典的区间dp,一开始只是想着要把两个字符串变成相同的,但其实先不用考虑第一个字符串,如果只想着构造一个S2,题意其实还更加明白,现在是S1——>S2,就可以简单的想着把S2直接构造出来,然后看看S1和S2有多少相同的字母构造S2的时候,就是状态转移方程是

                         if(s2[i]==s2[k])  dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k][j])

如果S1和S2完全不相同的话,现在应该已经做完了

问题也在这,我本来以为去掉相同的就可以了,可是还不行,相同的段会把区间给断开,所以在区间里还得再求最小值,才能找到最优解。

#include <stdio.h>

#include<iostream>
#include <string.h>
#include <algorithm>


using namespace std;
 
char s1[105],s2[105];
int dp[105][105];
int ans[105],len;
 
int main()
{
    int t,tt;
    int i,j,k;
    while(cin>>s1>>s2)
    {
        len = strlen(s1);
        memset(dp,0,sizeof(dp));
        for(j = 0; j<len; j++)
        {
            for(i = j; i>=0; i--)
            {
                dp[i][j] = dp[i+1][j]+1;
                for(k = i+1; k<=j; k++)
                {
                    if(s2[i]==s2[k])
                        dp[i][j] = min(dp[i][j],(dp[i+1][k]+dp[k+1][j]));
                }
            }
        }
        for(i = 0; i<len; i++)
            ans[i] = dp[0][i];
        for(i = 0; i<len; i++)
        {
            if(s1[i] == s2[i])
                ans[i] = ans[i-1];
            else
            {
                for(j = 0; j<i; j++)
                    ans[i] = min(ans[i],ans[j]+dp[j+1][i]);
            }
        }
        printf("%d\n",ans[len-1]);
    }
 
    return 0;
}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值