标签:hdu
http://acm.hdu.edu.cn/showproblem.php?pid=3698
3 5 9 5 3 8 7 8 2 6 8 9 1 9 7 8 6 0 1 0 1 2 1 0 2 1 1 0 2 1 0 2 0 0
10
题意:就是每行选一个,上下两行需满足|j-k|≤f(i,j)+f(i+1,k).,问最小的cell和值。
分析:明显的dp,dp[i][j]表示到第i行选第j个的值,但是这样转移复杂度需要n*m*m,肯定会超时。
我们注意到|j-k|<=f(i,j)+f(i-1,k),那么对于i-1行的第k个我们更新[k-f(i-1,k),k+f(i-1,k)],对于第i行查询[j-f(i,j),j+f(i,j)],这样刚好满足的是要求的条件。
所以就用线段树维护一下查询区间最小值更新区间值就好。这样复杂度就是n*m*log(m)。。
/**
 * @author neko01
 */
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define clr(a) memset(a,0,sizeof a)
#define clr1(a) memset(a,-1,sizeof a)
#define dbg(a) printf("%d\n",a)
typedef pair<int,int> pp;
const double eps=1e-8;
const double pi=acos(-1.0);
const int INF=0x7fffffff;
const LL inf=(((LL)1)<<61)+5;
const int N=105;
const int M=5005;
int a[N][M];
int f[N][M];
int dp[N][M];
struct node{
    int l,r;
    int Min;
    int col;
}tree[M*4];
void build(int x,int l,int r)
{
    tree[x].l=l,tree[x].r=r;
    tree[x].Min=INF;
    tree[x].col=INF;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
inline void push_down(int x)
{
    if(tree[x].col!=INF)
    {
        tree[x<<1].col=min(tree[x].col,tree[x<<1].col);
        tree[x<<1|1].col=min(tree[x<<1|1].col,tree[x].col);
        tree[x<<1].Min=min(tree[x].col,tree[x<<1].Min);
        tree[x<<1|1].Min=min(tree[x].col,tree[x<<1|1].Min);
        tree[x].col=INF;
    }
}
void update(int x,int l,int r,int val)
{
    if(tree[x].l==l&&tree[x].r==r)
    {
        tree[x].Min=min(tree[x].Min,val);
        tree[x].col=min(tree[x].col,val);
        return;
    }
    push_down(x);
    int mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid) update(x<<1,l,r,val);
    else if(l>mid) update(x<<1|1,l,r,val);
    else
    {
        update(x<<1,l,mid,val);
        update(x<<1|1,mid+1,r,val);
    }
    tree[x].Min=min(tree[x<<1].Min,tree[x<<1|1].Min);
}
int query(int x,int l,int r)
{
    if(tree[x].l==l&&tree[x].r==r)
        return tree[x].Min;
    push_down(x);
    int mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid) return query(x<<1,l,r);
    else if(l>mid) return query(x<<1|1,l,r);
    else return min(query(x<<1,l,mid),query(x<<1|1,mid+1,r));
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&a[i][j]);
                if(i==1) dp[1][j]=a[i][j];
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&f[i][j]);
        for(int i=2;i<=n;i++)
        {
            build(1,1,m);
            for(int j=1;j<=m;j++)
            {
                int l=max(1,j-f[i-1][j]);
                int r=min(m,j+f[i-1][j]);
                update(1,l,r,dp[i-1][j]);
            }
            for(int j=1;j<=m;j++)
            {
                int l=max(1,j-f[i][j]);
                int r=min(m,j+f[i][j]);
                dp[i][j]=query(1,l,r)+a[i][j];
            }
        }
        int ans=INF;
        for(int i=1;i<=m;i++)
            ans=min(ans,dp[n][i]);
        printf("%d\n",ans);
    }
    return 0;
}
hdu3698 Let the light guide us dp+线段树优化
标签:hdu
原文地址:http://blog.csdn.net/neko01/article/details/40754175