zoukankan      html  css  js  c++  java
  • P1006 传纸条

    题目链接:

    P1006 传纸条

    思路

    第一种((O(n^2 cdot m^2))):

    设$ f[i][j][k][l] (为从小渊传到小轩的纸条到达)(i,j) (,从小轩传给小渊的纸条到达)(k,l)$的路径上取得的最大的好心程度和。

    从给定的起点出发走到指定位置的两条最短严格不相交路线。

    那么特别显然,转移方程是

    [f[i][j][k][l]=max( f[i][j-1][k-1][l] , f[i-1][j][k][l-1] , f[i][j-1][k][l-1] , f[i-1][j][k-1][l] )+a[i][j]+a[k][l] ]

    注意(j)要从(i+1)开始循环,因为要避免走重复的路,有空画个图解释一下

    60分代码

    错误原因:

    (m,n)很混乱

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<string>
    #include<cstring>
    using namespace std;
    inline int read() {
        char c = getchar();
        int x = 0, f = 1;
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int  f[51][51][51][51],m,n;
    int a[51][51];
    signed main() {
        cin>>m>>n;
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=m; ++j)
                cin>>a[i][j];
        for(int i=1; i<=m; ++i) {
            for(int j=1; j<=n; ++j) {
                for(int k=1; k<=m; ++k) {
                    for(int p=j+1; p<=n; ++p) {
                        f[i][j][k][p]=max(max(f[i][j-1][k-1][p],f[i-1][j][k][p-1] ),max(f[i][j-1][k][p-1],f[i-1][j][k-1][p]) )+a[i][j]+a[k][p];
                    }
                }
            }
        }
        //cout<<f[1][1][m][n];
        cout<<f[n][m-1][n-1][m];
        return 0;
    }
    

    100分代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<string>
    #include<cstring>
    using namespace std;
    inline int read() {
    	char c = getchar();
    	int x = 0, f = 1;
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    /*int max_ele(int a,int b,int c,int d){
        if (b>a)
            a = b;
        if (c>a)
            a = c;
        if (d>a)
            a = d;
        return a;
    }*/
    int  f[51][51][51][51],n,m;
    int a[51][51];
    
    signed main() {
    	cin>>n>>m;
    	for(int i=1; i<=n; ++i)
    		for(int j=1; j<=m; ++j)
    			cin>>a[i][j];
    	for(int i=1; i<=n; ++i) {
    		for(int j=1; j<=m; ++j) {
    			for(int k=1; k<=n; ++k) {
    				for(int l=j+1; l<=m; ++l) {
    					f[i][j][k][l]=max(max(f[i][j-1][k-1][l],f[i-1][j][k][l-1] ),max(f[i][j-1][k][l-1],f[i-1][j][k-1][l]) )+a[i][j]+a[k][l];
    					//f[i][j][k][l]=max_ele(f[i][j-1][k-1][l],f[i-1][j][k][l-1] ,f[i][j-1][k][l-1],f[i-1][j][k-1][l])+a[i][j]+a[k][l];
    				}
    			}
    		}
    	}
    	//cout<<f[1][1][n][m];
    	cout<<f[n][m-1][n-1][m];
    	return 0;
    }
    

    这种做法复杂度其实很高了,能过全是题水的原因

    做法二:

    来自luogu题解第一篇:传送门

    因为是从上方和从下方传纸条,为了方便,我们相当于从左上角连续传两张纸条,路径不重复,效果相同。

    从左上来看的话就只能向右或向下传纸条。

    那么两张纸条在过程中就一定在一条斜线上,而在一条斜线上纵坐标与横坐标相加相等。

    首先重要的就是三维F数组。

    第一维度维护的是在传的过程中纵坐标与横坐标的和。

    在同一斜线上,剩下表示两个点的从坐标就可以表示这两个点的位置。
    第二维度维护的是相对在左边的点的纵坐标。

    第三维度维护的是相对在右边的点的纵坐标。

    当查询一个情况时,只有四种情况可以到他

    F[sum][i][j]=max{F[sum-1][i][j]+F[k-1][i][j-1]+F[k-1][i-1][j]+F[k-1][i-1][j-1];

    最后再加上a数组里存的两个点的好感度即可

    include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=60;
    int a[maxn][maxn];
    int F[2*maxn][maxn][maxn];
    int main()
    {
      int m,n;
      scanf("%d%d",&m,&n);
      for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
          scanf("%d",&a[i][j]);
      //F[sum][i][j]=max{F[sum-1][i][j]...
      memset(F,-1,sizeof(F));//赋初值为-1 (原因在后面) 
      F[2][1][1]=0;//最初的点,在左上角,好感度为0 
      for(int k=3;k<m+n;k++)
        for(int i=1;i<n;i++)
          for(int j=i+1;j<=n;j++)
          {
            int s=F[k][i][j];
            if(F[k-1][i][j]>s)s=F[k-1][i][j];
            if(F[k-1][i-1][j]>s)s=F[k-1][i-1][j];
            if(F[k-1][i][j-1]>s)s=F[k-1][i][j-1];
            if(F[k-1][i-1][j-1]>s)s=F[k-1][i-1][j-1];
            if(s==-1)continue;//当s为-1时,说明四种情况都不能到该点,故不存在。 
            F[k][i][j]=s+a[k-i][i]+a[k-j][j];//该点的值为最大的前一个值与当前F[k][i][j]表示两点的值的和。 
          }
      printf("%d",F[m+n-1][n-1][n]);//因为i永远小于j,所以右下角的点不会求到,
      //但是到右下角只有一种情况,就是在右下角的上面和右下角的左边,直接输出就好了。 
      return 0;
     } 
    

    类似的题目:

    点这里传送

    $$Life quad is quad fantastic!$$
  • 相关阅读:
    1.数据结构《Pytorch神经网络高效入门教程》Deeplizard
    plt.figure()的使用,plt.plot(),plt.subplot(),plt.subplots()和图中图
    可变长参数
    np.linspace,numpy中的linspace()
    python和numpy中sum()函数的异同
    maven install 错误
    spring boot启动后执行方法
    java 定时任务多线程处理
    java 生成txt文件
    java 方法超时
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/10914748.html
Copyright © 2011-2022 走看看