列表

详情


NC16852. [NOI1998]围巾裁剪

描述

裁缝有一块非常珍贵的丝绸围巾。可惜的是,围巾的某些部分已经被蛀虫给咬坏了。裁缝当然不愿意就这么把围巾给丢了,于是,他想把围巾给裁成两块小围巾送给他的两个女儿。自然,两块小围巾的面积之和越大越好。

    这块围巾是一个正三角形,三条边被均匀地分成了N段,即这个正三角形被均匀地分成了N2个单元,每个单元是一个面积为1的正三角形。图一所示为一个N=5的围巾,图中带阴影的单元表示被蛀虫咬坏的部分。从上往下看,围巾被分成了N行,第一行有1个单元,第二行有3个单元,其中有2个是形如D 的,有1个是形如Ñ 的(这两种三角形我们认为是形状相同的)。第三行有5个,其中有3个是形如D 的,有2个是形如Ñ 的……。用坐标(X,Y)给每个单元定位,第一行的单元的坐标为(1,1);第二行从左到右的三个单元的坐标依次为(2,1)、(2,2)、(2,3);…。

围巾的剪裁条件如下:
  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;
}

上一题