码迷,mamicode.com
首页 > 其他好文 > 详细

[NOIP2014]子矩阵解题报告

时间:2015-04-18 11:36:41      阅读:297      评论:0      收藏:0      [点我收藏+]

标签:dfs   dp   

这题看上去没啥思路,一看数据范围小的可怜,就算了下暴搜的时间复杂度O(C(16,8)?(C(16,8)+m3))108似乎没啥问题,然后就写了个暴搜,出了点数据发现T了,又加了个剪枝然后就A了。。
结果一看人家的代码全是DP。。让我有点蛋疼。
其实只要把暴搜的后半部分一改就可以了,把二维压成一维后,就有一个显然的DP方程:处理出选一列的代价lsi,选一对列的代价hs(i,j),设f(i,j)为选第i列,在第i列之前已经选了j-1列的最小代价,则显然

f(i,j)=lsi+min1k<i{ f(k,j?1)+hs(k,i) }
这道题虽然是普及组的题,但是也挺好的,让我明白把二维压到一维与直接在二维上做的巨大差别!这种思想以后我在处理矩阵的时候一定要时刻牢记!
Code(dfs):

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,r,c;
int a[20][20];
int ls[20],hs[20][20];
int list[20];
int ans=0x7fffffff;
inline void ldfs(int x,int last,int nowc,int nowsum){
    if(m-x<nowc||nowsum>=ans)return;
    if(x==m){
        ans=min(ans,nowsum);
        return;
    }
    ldfs(x+1,last,nowc,nowsum);
    if(nowc)ldfs(x+1,x,nowc-1,nowsum+ls[x]+hs[last][x]);
}
inline void hdfs(int x,int now){
    if(n-x<now)return;
    if(x==n){
        int i,j;
        memset(ls,0,sizeof(ls));
        for(i=m;i--;)
            for(j=r;--j;)
                ls[i]+=abs(a[list[j]][i]-a[list[j-1]][i]);
        int k;
        memset(hs,0,sizeof(hs));
        for(i=0;i<m;++i)
            for(j=i+1;j<m;++j)
                for(k=r;k--;)
                    hs[i][j]+=abs(a[list[k]][i]-a[list[k]][j]);
        ldfs(0,m-1,c,0);
        return;
    }
    hdfs(x+1,now);
    if(now){
        list[--now]=x;
        hdfs(x+1,now);
    }
}
int main(){
    freopen("submatrix.in","r",stdin);
    freopen("submatrix.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&r,&c);
    int i,j;
    for(i=0;i<n;++i)
        for(j=0;j<m;++j)
            scanf("%d",a[i]+j);
    hdfs(0,r);
    printf("%d\n",ans);
}

Code(DP):

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,r,c;
int a[20][20];
int ls[20],hs[20][20];
int list[20];
int ans=0x7fffffff;
int f[20][20];
inline void ldfs(int x,int last,int nowc,int nowsum){
    int i,j;
    for(i=0;i<m;++i)
        for(j=0;j<=c;++j)
            f[i][j]=1E9;
    for(i=0;i<m;++i)f[0][0]=0,f[i][1]=ls[i];
    int k;
    for(i=1;i<m;++i)
        for(j=2;j<=c;++j){
            for(k=0;k<i;++k)f[i][j]=min(f[i][j],f[k][j-1]+hs[k][i]);
            f[i][j]+=ls[i];
        }
    for(i=0;i<m;++i)ans=min(ans,f[i][c]);
}
inline void hdfs(int x,int now){
    if(n-x<now)return;
    if(x==n){
        int i,j;
        memset(ls,0,sizeof(ls));
        for(i=m;i--;)
            for(j=r;--j;)
                ls[i]+=abs(a[list[j]][i]-a[list[j-1]][i]);
        int k;
        memset(hs,0,sizeof(hs));
        for(i=0;i<m;++i)
            for(j=i+1;j<m;++j)
                for(k=r;k--;)
                    hs[i][j]+=abs(a[list[k]][i]-a[list[k]][j]);
        ldfs(0,m-1,c,0);
        return;
    }
    hdfs(x+1,now);
    if(now){
        list[--now]=x;
        hdfs(x+1,now);
    }
}
int main(){
    freopen("submatrix.in","r",stdin);
    freopen("submatrix.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&r,&c);
    int i,j;
    for(i=0;i<n;++i)
        for(j=0;j<m;++j)
            scanf("%d",a[i]+j);
    hdfs(0,r);
    printf("%d\n",ans);
}

[NOIP2014]子矩阵解题报告

标签:dfs   dp   

原文地址:http://blog.csdn.net/ta201314/article/details/45111249

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!