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