NC16852. [NOI1998]围巾裁剪
描述
裁缝有一块非常珍贵的丝绸围巾。可惜的是,围巾的某些部分已经被蛀虫给咬坏了。裁缝当然不愿意就这么把围巾给丢了,于是,他想把围巾给裁成两块小围巾送给他的两个女儿。自然,两块小围巾的面积之和越大越好。
围巾的剪裁条件如下:
1.裁成的两块小围巾形状与原来的大围巾完全相同,都是正三角形。
2.每一块小围巾里都不存在被蛀虫咬坏的部分。
3.裁剪时必须沿着单元的边界裁剪。
4.要求两块小围巾的面积的总和最大。
图一中,最优的裁剪方法已经用粗线画了出来,面积和为4+9=13。
现在需要你编一个程序来帮助裁缝解决这个问题。
输入描述
第一行为一个整数N(1 ≤ N ≤ 100),表示这块围巾总共被分成了N2个单元。第二行为一个整数M(0 ≤ M ≤ N2-2),表示这块围巾共有M个单元被蛀虫咬坏了。接下的M行,每一行有两个正整数X和Y,为这M个被蛀虫咬坏的单元的坐标。
输入文件中同一行相邻两项之间用一个或多个空格隔开。
输出描述
仅含一个整数,为你所找到的裁出两块小围巾面积总和的最大值。
示例1
输入:
5 5 3 2 4 1 4 4 5 4 5 2
输出:
13
Pascal(fpc 3.0.2) 解法, 执行用时: 79ms, 内存消耗: 632K, 提交时间: 2019-01-07 18:11:52
program cut; var f,g:array[-10..200,-10..200] of longint; map,map1:array[-10..200,-10..200] of boolean; i,j,k,n,m,x,y,max:longint; function min(a,b:longint):longint; begin if a<b then exit(a) else exit(b); end; function jisuan(x,y:longint):longint; var i,j,max:longint; begin fillchar(f,sizeof(f),0); fillchar(g,sizeof(g),0); max:=0; for i := x to y do for j :=1 to 2*i-1 do if map[i,j] then begin f[i,j]:=1;g[i,j]:=1;end; for i := y-1 downto x do for j :=1 to 2*i-1 do if j mod 2=1 then if f[i,j]=1 then if map[i+1,j+1] then begin f[i,j]:=min(f[i+1,j],f[i+1,j+2])+1; if f[i,j]>max then max:=f[i,j]; end; for i :=x+1 downto y do for j :=1 to 2*i-1 do if j mod 2=0 then if g[i,j]=1 then if map[i-1,j-1] then begin g[i,j]:=min(g[i-1,j-2],g[i-1,j])+1; if g[i,j]>max then max:=g[i,j]; end; exit(max); end; procedure doit; var ans1,ans2,i:longint; begin for i :=1 to n-1 do begin ans1:=jisuan(1,i); ans2:=jisuan(i+1,n); if sqr(ans1)+sqr(ans2)>max then max:=sqr(ans1)+sqr(ans2); end; end; procedure xuan;{把三角形旋转120°} var x,y,q,p,i,j:longint; begin x:=0;y:=0; fillchar(map1,sizeof(map1),true); while y<>2*n-1 do begin x:=x+1;y:=0; p:=n;q:=x*2-1; while y<>2*x-1 do begin y:=y+1; map1[x,y]:=map[p,q]; if q mod 2=1 then q:=q-1 else begin p:=p-1;q:=q-1;end; end; end; map:=map1; end; begin reset(input); rewrite(output); readln(n); for i := 1 to n do begin for j := 1 to 2*n-1 do map[i,j]:=true; end; readln(m); for i :=1 to m do begin readln(x,y); map[x,y]:=false; end; for i :=1 to 3 do begin doit; if i<>3 then xuan; end; writeln(max); close(input); close(output); end.
C++11(clang++ 3.9) 解法, 执行用时: 2ms, 内存消耗: 396K, 提交时间: 2020-08-17 10:19:29
#include<cstdio> #include<cstring> using namespace std; const int N=110; int n,m; bool a[N][N]; int data[N][N]; int min1(int x,int y){ return x<y?x:y; } int f(int i,int j){ if(data[i][j]!=-1) return data[i][j]; if(i==n){ data[i][j]=1; return 1; } if(!a[i][j]){ data[i][j]=0; return 0; } if(a[i+1][j+1]){ data[i][j]=min1(f(i+1,j),f(i+1,j+2))+1; return data[i][j]; }else{ data[i][j]=1; return 1; } } int main(){ //freopen("D.in","r",stdin); scanf("%d%d",&n,&m); memset(a,true,sizeof a); int x,y; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); a[x][y]=false; } memset(data,-1,sizeof data); int ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<2*i;j++){ int k=f(i,j); if(k>ans){ ans=k;x=i;y=j; } } } int s=ans*ans,S=n*n; if(s+m==S){ printf("%d",s-2*ans+2); return 0; } for(int i=0;i<ans;i++){ for(int j=0;j<2*(i+1);j++){ a[x+i][y+j]=false; } } memset(data,-1,sizeof data); ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<2*i;j++){ int k=f(i,j); if(k>ans){ ans=k;x=i;y=j; } } } ans=ans*ans; printf("%d\n",ans+s); return 0; }
C++14(g++5.4) 解法, 执行用时: 2ms, 内存消耗: 376K, 提交时间: 2020-08-17 09:46:17
#include<cstdio> #include<cstring> using namespace std; const int N=110; int n,m; bool a[N][N]; int data[N][N]; int min1(int x,int y){ return x<y?x:y; } int f(int i,int j){ if(data[i][j]!=-1) return data[i][j]; if(i==n){ data[i][j]=1; return 1; } if(!a[i][j]){ data[i][j]=0; return 0; } if(a[i+1][j+1]){ data[i][j]=min1(f(i+1,j),f(i+1,j+2))+1; return data[i][j]; }else{ data[i][j]=1; return 1; } } int main(){ scanf("%d%d",&n,&m); memset(a,true,sizeof a); int x,y; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); a[x][y]=false; } memset(data,-1,sizeof data); int ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<2*i;j++){ int k=f(i,j); if(k>ans){ ans=k;x=i;y=j; } } } int s=ans*ans,S=n*n; // for(int i=1;i<=n;i++){ // for(int j=1;j<2*i;j++){ // printf("%d ",data[i][j]); // } // puts(""); // } if(s+m==S){ printf("%d",s-2*ans+2); return 0; } for(int i=0;i<ans;i++){ for(int j=0;j<2*(i+1);j++){ a[x+i][y+j]=false; } } memset(data,-1,sizeof data); ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<2*i;j++){ int k=f(i,j); if(k>ans){ ans=k;x=i;y=j; } } } ans=ans*ans; printf("%d\n",ans+s); return 0; }