HDU 3698-Let the light guide us(线段树+DP)愿圣光忽悠你

来源:互联网 发布:java 图片文字合成 编辑:程序博客网 时间:2024/05/21 10:56

题意:

给定两个矩阵,第一个矩阵代表时间,第二个矩阵代表距离。给出约束的公式,询问在每一行都造一个圣光塔最少花费多少时间!

思路:

对于题目中给的条件 |J-K| <=f[i][j] +f[i+1] [k] 若拆掉绝对值可以得到 K+f[i+1][k] >= j- f[i] [j]        k-f[i+1][k] <= j+f[i][j]

若M很小的话 ,我们自然可以通过一个很好看出来的 DP来AC 。DP的方程为:

 dp[i ][ j] = min(  dp[i ] [j]  , dp[i-1] [k ] + timed[ i] [j] )  ,但是如果我们暴力枚举的话是m*m *n 的复杂度,显然会TLE

再重新考虑不等式约束,可以发现K的范围只是在 j-f[i][j]  ,f+ f[i][j]之间 ,也就是我们每次DP转移方程 是在这个范围内取得最小值。

对于这个问题显然线段树就可以搞定!维护区间最小值

#include<algorithm>#include<iostream>#include<sstream>#include<string.h>#include<stdio.h>#include<math.h>#include<vector>#include<string>#include<queue>#include<map>using namespace std;const int inf=0x3f3f3f3f;int n,m,ans;const int maxn=5005;int timed[105][maxn];int dp[105];int f[105][maxn];struct node{    int left,right;    int minn,val;}tree[maxn*4];void build(int i,int left,int right){    tree[i].left=left,tree[i].right=right;    tree[i].minn=inf,tree[i].val=inf ;    if(left==right) return;    int mid=(left+right)>>1;    build(i<<1,left,mid);    build(i<<1|1,mid+1,right);    return ;}void pushdown(int i){    int mid=tree[i].left+tree[i].right;    mid=mid>>1;    tree[i<<1].val=  min(tree[i<<1].val,tree[i].val);    tree[i<<1|1].val=min(tree[i<<1|1].val,tree[i].val);    tree[i<<1].minn=  min(tree[i<<1].minn,tree[i].val);    tree[i<<1|1].minn=min(tree[i<<1|1].minn,tree[i].val);    tree[i].val=inf;}void update(int i,int left,int right,int w){    if(tree[i].left==left&&tree[i].right==right)    {        tree[i].val=min(tree[i].val,w);        tree[i].minn=min(tree[i].minn,w);        return ;    }    if(tree[i].val!=inf)    {        pushdown(i);    }    int mid=(tree[i].left+tree[i].right)>>1;    if(right<=mid)        update(i<<1,left,right,w);    else if(left>mid)        update(i<<1|1,left,right,w);    else    {        update(i<<1,left,mid,w);        update(i<<1|1,mid+1,right,w);    }    tree[i].minn=min(tree[i<<1].minn,tree[i<<1|1].minn);    return ;}void query(int i,int left,int right){    if(tree[i].left==left&&tree[i].right==right)    {        ans=min(ans,tree[i].minn);        return ;    }    int mid=(tree[i].left+tree[i].right)>>1;    if(tree[i].val!=inf)    {        pushdown(i);    }    if(right<=mid)        query(i<<1,left,right);    else if(left>mid)        query(i<<1|1,left,right);    else    {        query(i<<1,left,mid);        query(i<<1|1,mid+1,right);    }    tree[i].minn=min(tree[i<<1].minn,tree[i<<1|1].minn);    return ;}int main(){    while(~scanf("%d%d",&n,&m)&&(n+m))    {        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&timed[i][j]);            }        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&f[i][j]);            }        }        for(int i=1;i<=m;i++)        {            dp[i]=timed[1][i];        }        for(int i=2;i<=n;i++)        {            build(1,1,m);            for(int j=1;j<=m;j++)            {                int l=max(j-f[i-1][j],1);                int r=min(j+f[i-1][j],m);                update(1,l,r,dp[ j ]);            }            for(int j=1;j<=m;j++)            {                int l=max(j-f[i][j],1);                int r=min(j+f[i][j],m);                ans=inf;                query(1,l,r);                dp[j]=ans+timed[i][j];            }      //  for(int i=1;i<=m;i++)      //      printf("%d ",dp[i]);      //  printf("\n");        }        int minnn=inf;        for(int i=1;i<=m;i++)        {            minnn=min(minnn,dp[i]);        }        printf("%d\n",minnn);    }}


0 0
原创粉丝点击