NOIP2014 子矩阵

题目 

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#define UP(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;
const int INF=1000000000;
int g[25][25],f[25][25],dp[25][25],val[25][25];
int n,m,x,y,res;
int count(int a){
    int x=0;
    while(a){if(a&1)x++; a>>=1;}
    return x;
}
void DP(){
    UP(i,1,n)UP(j,i+1,n){
        val[i][j]=0;
        UP(k,1,y) val[i][j]+=abs(f[i][k]-f[j][k]);
    }
    UP(i,1,x)UP(j,i,n)dp[j][i]=INF;
    UP(i,1,n){
        dp[i][1]=0;
        UP(j,2,y)dp[i][1]+=abs(f[i][j]-f[i][j-1]);
    }
    UP(i,2,x)UP(j,i,n)UP(k,i-1,j-1)
        dp[j][i]=min(dp[j][i], dp[k][i-1]+val[k][j]+dp[j][1]);
    UP(i,x,n) res=min(res, dp[i][x]);
}
int main(){
    scanf("%d%d%d%d",&n,&m,&x,&y);
    UP(i,1,n)UP(j,1,m)scanf("%d",&g[i][j]);
    res=INF;
    UP(i,0,(1<<m)-1){
        if(count(i)!=y) continue;
        int r=0;
        UP(j,0,m-1){
            if( ((i>>j)&1) ==0) continue;
            ++r;
            UP(k,1,n) f[k][r]=g[k][j+1];
        }
        DP();
    }
    printf("%d\n",res);
    return 0;
}

  

//穷举 60分

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define UP(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;
const int INF=1000000000;
const int N=20;
int g[N][N],f[N][N],a[N][N],T;
int n,m,x,y,X=INF;
int count(int a){
    int x=0;
    while(a){if(a&1)x++; a>>=1;}
    return x;
}
void Calc(){
    int t=0;
    UP(i,1,x)UP(j,1,y)t+=(abs(a[i][j]-a[i-1][j])+abs(a[i][j]-a[i][j-1]));
    UP(i,1,x)t-=a[i][1];
    UP(j,1,y)t-=a[1][j];
    X=min(X,t);
}

int main(){
    scanf("%d%d%d%d",&n,&m,&x,&y);
    UP(i,1,n)UP(j,1,m)scanf("%d",&g[i][j]);
    UP(i,0,(1<<m)-1){
        if(count(i)!=y)continue;
        int c=0;
        UP(j,0,m-1){
            if(((i>>j)&1)==0)continue;
            ++c; UP(k,1,n)f[k][c]=g[k][j+1];
        }
        UP(p,0,(1<<n)-1){
            if(count(p)!=x)continue;
            int r=0;
            UP(q,0,n-1){
                if(((p>>q)&1)==0)continue;
                ++r; UP(d,1,y)a[r][d]=f[q+1][d];
            }
            Calc();
        }
    }
    printf("%d\n",X);
    return 0;
}

  

 

 

 

var
    n,m,r,c,i,j,he,ans:longint;
    a,b:array[1..20,1..20] of longint;
    h,l:array[1..20] of longint;

procedure qc;
var i,j:longint;
begin
    he:=0;
    for i:=1 to r do
        for j:=1 to c do
        begin
            if i+1<=r then he:=he+abs(b[i,j]-b[i+1,j]);
            if j+1<=c then he:=he+abs(b[i,j]-b[i,j+1]);
        end;
end;

procedure cl(x,k:longint);
var i,j:longint;
begin
    if x=c+1 then
    begin
        for i:=1 to r do
            for j:=1 to c do
                b[i,j]:=(a[h[i],l[j]]);
        qc;
        if ans>he then ans:=he;
    end;
    for i:=k to m do
    begin
        l[x]:=i;  cl(x+1,i+1);
    end;
end;

procedure ch(y,k1:longint);
var i:longint;
begin
    if y=r+1 then cl(1,1);
    for i:=k1 to n do
    begin
        h[y]:=i; ch(y+1,i+1);
    end;
end;

begin
    readln(n,m,r,c);
    for i:=1 to n do
        for j:=1 to m do read(a[i,j]);
    ans:=maxlongint;
    ch(1,1);
    writeln(ans);
end.

 

 

 

 调试版

uses math;
var
    a,b,s3,s4:array[0..20,0..20] of longint;
    s1,s2:array[0..20] of longint;
    i,j,m,n,r,c,ans:longint;
procedure dfs(x,y:longint);//x作为第y列备选
var
    i,j,k,l:longint;
begin
    s1[y]:=x;
    if y<r then
        for i:=x+1 to n do dfs(i,y+1)
    else
    begin
        fillchar(b,sizeof(b),0);
        for i:=1 to r do
            for j:=1 to m do b[i,j]:=a[s1[i],j];
        fillchar(s2,sizeof(s2),0);
        for i:=1 to m do//每列各行差的和
            for j:=1 to r-1 do inc(s2[i],abs(b[j+1,i]-b[j,i]));
        fillchar(s3,sizeof(s3),0);
        for i:=1 to m-1 do
            for j:=i+1 to m do//两列之间各行差值之和
                for k:=1 to r do inc(s3[i,j],abs(b[k,i]-b[k,j]));
        fillchar(s4,sizeof(s4),$3f);
        for i:=0 to m do s4[i,0]:=0;
        for i:=1 to m do
            for j:=1 to min(c,i) do
                for k:=j-1 to i-1 do s4[i,j]:=min(s4[i,j],s4[k,j-1]+s2[i]+s3[k,i]);
        l:=999;
        for i:=1 to m do l:=min(l,s4[i,c]);
        if l=34 then
        begin
            for i:=0 to 5 do write(s1[i]:3); writeln;writeln;
            for i:=0 to 5 do write(s2[i]:3); writeln;writeln;
            for i:=0 to 5 do
            begin
                for j:=0 to 5 do write(s3[i,j]:3); writeln;
            end;
            writeln;
            for i:=0 to 5 do
            begin
                for j:=0 to 5 do write(s4[i,j]:13); writeln;
            end;
            halt;
        end;
        ans:=min(ans,l);
    end;
end;
begin
    readln(n,m,r,c);
    ans:=999;
    for i:=1 to n do
        for j:=1 to m do read(a[i,j]);
    dfs(0,0);
    
    //writeln(ans);
end.

 

result

5 5 3 4
9 3 3 3 9
9 4 8 7 4
1 7 4 6 6
6 8 5 6 9
7 4 5 6 1


9 3 3 3 9
1 7 4 6 6
6 8 5 6 9

  0  1  3  4  0  0

  0 13  5  2  3  6

  0  0  0  0  0  0
  0  0 14 10 11  8
  0  0  0  6  3  8
  0  0  0  0  3 12
  0  0  0  0  0  9
  0  0  0  0  0  0

  0 9999   9999   9999   9999   9999
  0   13   9999   9999   9999   9999
  0    5     32   9999   9999   9999
  0    2     13     40   9999   9999
  0    3      8     19     46   9999
  0    6     18     23     34     61

 

posted @ 2015-10-18 20:58  qilinart  阅读(426)  评论(0编辑  收藏  举报