曼哈顿距离(manhattan)

问题 C: 曼哈顿距离(manhattan)
时间限制: 2 Sec 内存限制: 512 MB

题目描述
现在我们建立一个n维的直角坐标系,每个点可以用它的坐标 (x1,x2,,xn) ( x 1 , x 2 , ⋯ , x n ) 来表示。如果我们设定每一维坐标都必须是不超过m的正整数,那么一共就有 mn m n 个点。
对于两个点 (a1,a2,,an) ( a 1 , a 2 , ⋯ , a n ) (b1,b2,,bn) ( b 1 , b 2 , ⋯ , b n ) ,我们定义 ni=1|aibi| ∑ i = 1 n | a i − b i | ,即 |a1b1|+|a2b2|++|anbn| | a 1 − b 1 | + | a 2 − b 2 | + ⋯ + | a n − b n | ,为这两个点的曼哈顿距离。容易看出,两个点的距离至少为 0 0 ,至多为 n(m1) n ( m − 1 )
mn m n 个点中的每个点都具有一个权值。你需要对于每个点,对于每个满足 0dn(m1) 0 ≤ d ≤ n ( m − 1 ) d d ,求出和这个点距离为 d d 的所有点的权值之和。(如果不存在这样的点则应输出 0 0
输入
第一行输入两个正整数 n,m n , m ,用空格隔开。
接下来 mn m n 行,每行一个正整数,表示每个点的权值。输入是按照坐标序列的字典序排列的,即先输入点 (1,1,,1,1) ( 1 , 1 , ⋯ , 1 , 1 ) 的权值,再输入 (1,1,,1,2) ( 1 , 1 , ⋯ , 1 , 2 ) 的权值,……,再输入 (1,1,,1,m) ( 1 , 1 , ⋯ , 1 , m ) 的权值,再输入 (1,1,,2,1) ( 1 , 1 , ⋯ , 2 , 1 ) 的权值……
输出
输出 mn m n 行,每行表示一个点。每行有 n(m1)+1 n ( m − 1 ) + 1 个整数,依次表示和这个点距离为 0,1,,n(m1) 0 , 1 , ⋯ , n ( m − 1 ) 的所有点的权值之和。
输出的点的顺序应与输入相同;同一行相邻的两个整数之间应当用恰好一个空格隔开。
样例输入
2 3
9
8
7
6
5
4
3
2
1
样例输出
9 14 15 6 1
8 21 12 4 0
7 12 15 8 3
6 17 14 8 0
5 20 20 0 0
4 13 16 12 0
3 8 15 12 7
2 9 18 16 0
1 6 15 14 9
提示
曼哈顿距离(manhattan)_第1张图片
题解:
dp[i][j][k] d p [ i ] [ j ] [ k ] i i 维,第 j j 个点,当前距离为 k k
那dp转移也非常简单,直接枚举相邻的点进行转移
注意第一维要滚动数组,否则会爆空间
Code:

#include
#include
#include
#define N 1000005
#define M 70005 
using namespace std;
int Pow[N],dp[2][M][205],a[N],num[M][105],n,m,x[1010];
int main()
{
    scanf("%d%d",&n,&m);
    if(n==1)
    {
        for(int i=1;i<=m;i++)scanf("%d",&x[i]);
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<m;j++)
            {
                int ans=0;
                if(i>j)ans+=x[i-j];
                if(i+j<=m&&j)ans+=x[i+j];
                if(j!=m-1)printf("%d ",ans);else
                    printf("%d\n",ans);
            }
        }
    }else
    {
        int Q=1;
        for(int i=1;i<=n;i++)Q=Q*m;
        for(int i=0;iint now=n,t=i;
            for(int j=1;j<=n;j++)num[i][j]=1;
            while(t)
            {
                num[i][now]+=t%m;
                t/=m;
                now--;
            }
            scanf("%d",&dp[0][i][0]);
        }
        Pow[n]=1;
        for(int i=n-1;i;i--)Pow[i]=Pow[i+1]*m;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;jfor(int k=0;k<=n*(m-1);k++)
                    for(int d=0;d<m;d++)
                    {
                        if(k+d>n*(m-1))continue;
                        if(num[j][i]+d<=m)
                            dp[i%2][j][k+d]+=dp[(i-1)%2][j+d*Pow[i]][k];
                        if(num[j][i]-d>0&&d)
                            dp[i%2][j][k+d]+=dp[(i-1)%2][j-d*Pow[i]][k];
                    }
            for(int j=0;jfor(int k=0;k<=n*(m-1);k++)
                    dp[(i-1)%2][j][k]=0;
        }
        for(int i=0;ifor(int j=0;j<=n*(m-1);j++)
                if(j*(m-1))printf("%d ",dp[n%2][i][j]);else
                    printf("%d\n",dp[n%2][i][j]);
    }
    return 0;
}

你可能感兴趣的:(=====dp=====,#,基本dp)