zoukankan      html  css  js  c++  java
  • hdu 3698 UVA1490 Let the light guide us 线段树优化DP

    题目链接 and 题目大意

    hdu3698
    但是 hdu的数据比较弱,所以在这luogu提交吧UVA1490 Let the light guide us
    有一个(n*m)的平原,要求每行选一个点,选(n)个点建造塔楼。
    平原上每个点都有他自己的花费时间和魔法值。

    为了正确控制塔楼,我们必须保证连续两排的每两座塔共用一个共同的魔法区域。
    也就是要求每两行相邻的点都满足如下关系:
    如果第(i)行选(j),第(i+1)行选(k),则需(|j-k|≤f(i,j)+f(i+1,k))
    问花费的总时间最少为多少?
    输入(n,m)
    再输入两个(n*m)的矩阵。
    第一个矩阵 $T[i][j] $表示的是花费时间,
    第二个矩阵 (f[i][j]) 表示的是魔法值

    思路

    如果(m<=100),那么这题就是个(O(n*m{2}))的沙比提

    for (int k = 2; k <= n; ++k) {
    			for (int i = 1; i <= m; ++i) {
    				for (int j = 1 ; j <= m; ++ j) {
    					if (abs(i - j) <= f[k][i] + f[k - 1][j] ) {
    						dp[k][i] = min(dp[k][i], dp[k - 1][j]);
    					}
    				}
    				dp[k][i] += t[k][i];
    			}
    		}
    


    但她并是不,(m<=1000)
    考虑如何优化一下
    $abs(i - j) <= f[k][i] + f[k - 1][j] ( )abs(i-j)(就是)i(和)j(之间的距离 就是)f[k][i] +f[k-1][j]$ 要大于i和j之间的距离(这里可以当成数轴上面)
    我们先看(k)这一行
    他能给下一行(也就是k+1)提供价值的区间至少为([i-f[k][i],i+f[k][i])),或者更大
    我们再看(k+1)这一行
    他能取到的区间(也就是k)的区间至少为([j-f[k+1][j],j+f[k+1][j])),或者更大
    如果他们的区间有交集,则说明他们可以由(k)(k+1)转移
    这个就可以用一颗区间加数,区间求min的线段树维护一下
    复杂度(O(n*mlogm))
    hdu数据很水,要去luogu测!!!
    当然,dp方程你可以压维,但压不压的没有啥意义反正你都开了两个一样大的数组了,多开一个又杂

    两份代码

    暴力代码(n*m*m)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int maxn = 107;
    const int maxm = 5007;
    const int inf = 0x3f3f3f3f;
    int n, m, t[maxn][maxm], f[maxn][maxm], dp[maxn][maxm];
    
    int read() {
    	int x = 0, f = 1; char s = getchar();
    	for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
    	for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
    	return x * f;
    }
    int abs(int a) {
    	return a > 0 ? a : -a;
    }
    
    int main() {
    	while (233) {
    		// read
    		n = read(), m = read();
    		if (n == 0 && m == 0) break;
    		for (int i = 1; i <= n; ++i)
    			for (int j = 1; j <= m; ++j)
    				t[i][j] = read();
    		for (int i = 1; i <= n; ++i)
    			for (int j = 1; j <= m; ++j)
    				f[i][j] = read();
    
    		//init
    		memset(dp, inf, sizeof(dp));
    		for (int i = 1; i <= m; ++i)
    			dp[1][i] = t[1][i];
    
    		//dp
    		for (int k = 2; k <= n; ++k) {
    			for (int i = 1; i <= m; ++i) {
    				for (int j = 1 ; j <= m; ++ j) {
    					if (abs(i - j) <= f[k][i] + f[k - 1][j] ) {
    						dp[k][i] = min(dp[k][i], dp[k - 1][j]);
    					}
    				}
    				dp[k][i] += t[k][i];
    			}
    		}
    
    		//printf
    		int ans = inf;
    		for (int i = 1; i <= n; ++i)
    			ans = min(ans, dp[n][i]);
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    线段树优化(n*m*logm) \

    #include <bits/stdc++.h>
    #define ls rt<<1
    #define rs rt<<1|1
    using namespace std;
    const int maxn=107;
    const int maxm=5007;
    const int inf=0x7fffffff;
    int n,m,a[maxn][maxm],b[maxn][maxm],f[maxn][maxm];
    struct node {
        int l,r;
        int mi,lazy;
    }e[maxm<<4];
    int read() {
        int x = 0, f = 1; char s = getchar();
        for (; s < '0' || s > '9'; s = getchar()) if (s == '-') f = -1;
        for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
        return x * f;
    }
    void build(int l,int r,int rt) {
        e[rt].l=l,e[rt].r=r,e[rt].mi=inf,e[rt].lazy=inf;
        if(l==r) return;
        int mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
    }
    void pushup(int rt) {
        e[rt].mi=min(e[ls].mi,e[rs].mi);
    }
    void pushdown(int rt) {
        if(e[rt].lazy!=inf) {
            e[ls].lazy=min(e[ls].lazy,e[rt].lazy);
            e[rs].lazy=min(e[rs].lazy,e[rt].lazy);
            e[ls].mi=min(e[ls].mi,e[ls].lazy);
            e[rs].mi=min(e[rs].mi,e[rs].lazy);
            e[rt].lazy=inf;
        }
    }
    void update(int L,int R,int k,int rt) {
        if(L<=e[rt].l&&e[rt].r<=R) {
            e[rt].lazy=min(e[rt].lazy,k);
            e[rt].mi=min(e[rt].mi,e[rt].lazy);
            return;
        }
        pushdown(rt);
        int mid=(e[rt].l+e[rt].r)>>1;
        if(L<=mid) update(L,R,k,ls);
        if(R>mid) update(L,R,k,rs);
        pushup(rt);
    }
    int query(int L,int R,int rt) {
        if(L<=e[rt].l&&e[rt].r<=R) {
            return e[rt].mi;
        }
        pushdown(rt);
        int mid=(e[rt].l+e[rt].r)>>1,ans=inf;
        if(L<=mid) ans=min(ans,query(L,R,ls));
        if(R>mid) ans=min(ans,query(L,R,rs));
        pushup(rt);
        return ans;
    }
    void debug1() {
        printf("debug
    ");
        printf("               %d
    ", e[1].mi);
        printf("       %d               %d
    ", e[2].mi, e[3].mi );
        printf("   %d       %d       %d       %d
    ", e[4].mi, e[5].mi, e[6].mi, e[7].mi );
        printf(" %d   %d   %d   %d   %d   %d   %d   %d
    ", e[8].mi,
         e[9].mi, e[10].mi, e[11].mi, e[12].mi, e[13].mi, e[14].mi, e[15].mi);
    }
    void debug()
    {
        for(int i=1;i<=n;++i,puts(""))
            for(int j=1;j<=m;++j)
                cout<<f[i][j]<<" ";
    }
    int main()
    {
        while(1)
        {
            n=read(),m=read();
            if(n==0 && m==0) return 0;
            for(int i=1;i<=n;++i)
                for(int j=1;j<=m;++j)
                    a[i][j]=read();
            for(int i=1;i<=n;++i)
                for(int j=1;j<=m;++j)
                    b[i][j]=read();
            for(int i=1;i<=m;++i)
                f[1][i]=a[1][i];
            for(int i=2;i<=n;++i) {
                build(1,m,1);
                for(int j=1;j<=m;++j) {
                    int l=max(1,j-b[i-1][j]),r=min(m,j+b[i-1][j]);
                    update(l,r,f[i-1][j],1);
                }
                for(int j=1;j<=m;++j) {
                    int l=max(1,j-b[i][j]),r=min(m,j+b[i][j]);
                    f[i][j]=query(l,r,1)+a[i][j];
                }
            }
            int ans=inf;
            for(int i=1;i<=m;++i)
                ans=min(ans,f[n][i]);
            printf("%d
    ", ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    在Ubuntu中通过update-alternatives切换软件版本
    SCons: 替代 make 和 makefile 及 javac 的极好用的c、c++、java 构建工具
    mongodb 的使用
    利用grub从ubuntu找回windows启动项
    How to Repair GRUB2 When Ubuntu Won’t Boot
    Redis vs Mongo vs mysql
    java script 的工具
    python 的弹框
    how to use greendao in android studio
    python yield的终极解释
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/9776239.html
Copyright © 2011-2022 走看看