#### HDU1160 FatMouse's Speed

题意是说,有两个整数序列\(W\)\(S\),要求找出一组下标\(m_1,m_2,m_3,···,m_n\),使得\[W[m_1]<W[m_2]<W[m_3]<···<W[m_n]\]\[S[m_1]>S[m_2]>S[m_3]>···>S[m_n]\]。下标的个数应尽可能地多。要求输出下标的个数以及被选出的下标。

对所有的\(W-S\)对进行排序,排序规则是按\(W\)为第一关键字从小到大排序,按\(S\)为第二关键字从大到小排序。而dp的方法其实跟LIS或者最大上升子序列和是很像的。关于输出被选取的下标,其实就是记录路径,只需要用一个pre数组记录下每一个下标的前驱,然后递归回去即可。

POJ1015 Jury Compromise

已有题解,不再赘述(确实是道好题)

POJ1015 - Jury Compromise

POJ1458 Common Subsequence

题如其名,最长公共子序列。直接写就可。

POJ1661 Help Jimmy

题目大意不知道怎么描述......

思路就是从最下面的平台往上dp,\(dp[i][0]\)表示的是从当前平台往左走一直到下一个平台的边缘(左边缘或右边缘)所需要的最小时间。\(dp[i][1]\)表示的是从当前平台往右走一直到下一个平台的边缘(左边缘或右边缘)所需要的最小时间。此处的最小时间指的是从最下面的平台一直递推到当前平台的总时间。

代码如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <list>
#include <set>
#include <utility>
#include <map>
#include <stack>
#include <cctype>
#include <string>
#include <queue>
#define mst(a,b) memset((a),(b),sizeof(a))
#define debug printf("debug\n")
#define INF 0x3f3f3f3f
#define IOS std::ios::sync_with_stdio(false)
const int maxn=1e5+5;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct node{
    int lef,rig;
    int hei;
    bool operator<(const node& nn)const{
        return hei>nn.hei;        //从大到小 
    }
};
node ns[1005];
int dp[1005][2];
int n,x,y,maxi;
void left_(int i)
{
    int k;
    for(k=i+1;k<=n+1;k++){        //k在i下面 
        if(ns[k].lef<=ns[i].lef
        &&ns[k].rig>=ns[i].lef
        &&ns[i].hei-ns[k].hei<=maxi){
            if(k==n+1)
                dp[i][0]=ns[i].hei-ns[k].hei;
            else    
                dp[i][0]=ns[i].hei-ns[k].hei+min(dp[k][0]+ns[i].lef-ns[k].lef,dp[k][1]+ns[k].rig-ns[i].lef);
            return ;
        }
    }
    if(ns[i].hei-ns[k].hei>maxi)
        dp[i][0]=INF;
    return ;
}
void right_(int i)
{
    int k;
    for(k=i+1;k<=n+1;k++){        //k在i下面 
        if(ns[k].lef<=ns[i].rig
        &&ns[k].rig>=ns[i].rig
        &&ns[i].hei-ns[k].hei<=maxi){
            if(k==n+1)
                dp[i][1]=ns[i].hei-ns[k].hei;
            else    
                dp[i][1]=ns[i].hei-ns[k].hei+min(dp[k][0]+ns[i].rig-ns[k].lef,dp[k][1]+ns[k].rig-ns[i].rig);
            return ;
        }
    }
    if(ns[i].hei-ns[k].hei>maxi)
        dp[i][1]=INF;
    return ;
}
int main()
{
    IOS;
    int t;cin>>t;
    while(t--){
        mst(dp,0);
        cin>>n>>x>>y>>maxi;
        for(int i=1;i<=n;i++){
            cin>>ns[i].lef>>ns[i].rig>>ns[i].hei;
        }
        sort(ns+1,ns+1+n);
        dp[n+1][0]=dp[n+1][1]=0;
        ns[n+1].lef=-INF;ns[n+1].rig=INF;ns[n+1].hei=0;
        ns[0].lef=ns[0].rig=x;ns[0].hei=y;
        for(int i=n;i>=0;i--){
            left_(i);
            right_(i);
        }
        int ans=min(dp[0][1],dp[0][0]);        
        cout<<ans<<endl;
    }
    return 0;
}

POJ2533 Longest Ordered Subsequence

题如其名,直接转移即可。注意初始化。

POJ3186 Treats for the Cows

题意懒得描述了......

\(dp[i][j]\)表示的是区间\([i,j]\)所能获得的最大价值。

做法是直接转移过去即可。注意初始化和转移顺序。

HDU1078 FatMouse and the Cheese

题目大意是说,现在有\(n \times n\)个网格,这些网格中有若干个网格放有cheese。从网格\((0,0)\)出发,每次走到下一个放有cheese的地方,可以水平走、垂直走,可以回头,每次最多走\(k\)步;同时,每一次获得的cheese都应该比上一次多,问最终最多能得到多少cheese。

一开始想着状态要怎么转移,感觉这题的规则挺多,不太好转移......然而实际上只需要记忆化+爆搜+简单dp即可。

代码如下:

HDU2859 Phalanx

题目大意是说,从一个矩阵中找出一个关于自身右对角线(从右上到左下)对称的子矩阵,问能找到的符合要求的最大子矩阵的大小是多少。

\(dp[i][j]\)表示如果\((i,j)\)处的元素是某个子矩阵的左下角,那么对应的子矩阵的大小是多少。

代码如下:

POJ3616 Miking Time

将每一个时间段的结束时间加上休息时间,即可用最大上升子序列和的思路来做。

代码如下:

POJ3666 Making the Grade

题目大意是说,对于一个给定的序列,现在要把它变成递增的或递减的,每改动一个数要付出的代价为改动后的数与改动前的数的差的绝对值。问如何改动才能使得代价最小。

首先,这题的数据有点问题,只需要考虑递增的情况......

这题的状态转移也不太好想,甚至感觉有点......神奇。具体见代码及代码注释