zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:小奇的矩阵(matrix)(DP+数学)

    题目背景

    小奇总是在数学课上思考奇怪的问题。


    题目描述

    给定一个$n imes m$的矩阵,矩阵中的每个元素$a_{i,j}$为正整数。
    接下来规定:
        $1.$合法的路径初始从矩阵左上角出发,每次只能向右或向下走,终点为右下角。
        $2.$路径经过的$n+m-1$个格子中的元素为$A_1,A_2...A_{(n+m-1)}$,$Aavg$为$A_i$的平均数,路径的$V$值为$(n+m-1) imes sum limits_{i=1}^{n+m-1}{(A_i-Advg)}^2$
    求$V$值最小的合法路径,输出$V$值即可,有多组测试数据。


    输入格式

    第一行包含一个正整数$T$,表示数据组数。
    对于每组数据:
    第一行包含两个正整数$n$和$m$,表示矩阵的行数和列数。
    接下来$n$行,每行$m$个正整数$a_{i,j}$,描述这个矩阵。


    输出格式

    对于每次询问,输出一行一个整数表示要求的结果。


    样例

    样例输入:

    1
    2 2
    1 2
    3 4

    样例输出:

    14


    数据范围与提示

    对于$30\%$的数据$nleqslant 10$,$mleqslant 10$。
    有另外$40\%$的数据$nleqslant 15$,$mleqslant 15$,矩阵中的元素不大于$5$。
    对于$100\%$的数据$Tleqslant 5$,$nleqslant 30$,$mleqslant 30$,矩阵中的元素不大于$30$。


    题解

    又是令人头疼的数学,而数学题就得化式子(但是你说你知道方差公式那我也没辙)。

    那就来化式子:

    $(n+m-1)sum{(A_i-Aavg)}^2$
    $=|(n+m-1) imes sum({A_i}^2-2 imes A_i imes Aavg+{Aavg}^2)|$
    $=|(n+m-1) imes sum{A_i}^2-(n+m-1) imes 2 imes sum (A_i imes Aavg)+(n+m-1) imes sum{Aavg}^2|$
    $=|(n+m-1) imes sum{A_i}^2-(n+m-1) imes 2 imes frac{sum{A_i}^2}{n+m-1}+(n+m-1) imes frac{{Aavg}^2}{n+m-1}|$
    $=|-(n+m-1) imes sum{A_i^2}-{Aavg}^2|$
    $=|{Aavg}^2-(n+m-1) imes sum{A_i}^2|$

    我们又发现矩阵中元素不大于$30$,既然它出现,必然有它的意义。

    考虑从这里入手,我们现在就来考虑$DP$,定义dp[i][j][k]表示到点(i,j),和为k,平方和的最小值。

    那么状态转移方程即为:$dp[i][j][k]=min(dp[i-1][j][k-x[i][j]],dp[i][j-1][k-x[i][j]])+x[i][j] imes x[i][j]$

    而我们统计答案的时候只需要找$min(dp[n][m][i] imes (n+m-1)-i imes i)$即可。

    时间复杂度:$Theta(30 imes n imes m imes (n+m))$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int Map[50][50];
    int dp[50][50][2000];
    int ans,maxn;
    void pre_work()
    {
    	ans=1<<30;
    	memset(dp,0x3f,sizeof(dp));
    }
    int main()
    {
    	int T;
    	scanf("%d",&T);
    	while(T--)
    	{
    		pre_work();
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    				scanf("%d",&Map[i][j]);
    		dp[1][1][Map[1][1]]=Map[1][1]*Map[1][1];
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    				for(int k=Map[i][j];k<=(n+m-1)*30;k++)
    					dp[i][j][k]=min(dp[i][j][k],min(dp[i-1][j][k-Map[i][j]],dp[i][j-1][k-Map[i][j]])+Map[i][j]*Map[i][j]);
    		for(int i=Map[n][m];i<=(n+m-1)*30;i++)
    			if(dp[n][m][i]<1061109567)
    				ans=min(ans,dp[n][m][i]*(n+m-1)-i*i);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }

    rp++

  • 相关阅读:
    vscode 在linux中,切换语言模式快捷键
    转载大神的一篇文章----【如何选择开源许可证?】
    Kibana6.x.x——源码发布
    Kibana6.x.x——【Running "run:optimizeBuild" (run) task】出现警告信息
    linux系统为文件添加执行权限
    Kibana6.x.x——执行yarn build出现的警告信息记录
    Kibana6.x.x——导航权限控制入门
    poj 2187:Beauty Contest(计算几何,求凸包,最远点对)
    poj 2386:Lake Counting(简单DFS深搜)
    蓝桥杯 第三届C/C++预赛真题(10) 取球游戏(博弈)
  • 原文地址:https://www.cnblogs.com/wzc521/p/11421045.html
Copyright © 2011-2022 走看看