ACdream 1429 Rectangular Polygon

Problem Description

      A rectangular polygon is a polygon whose edges are all parallel to the coordinate axes. The polygon must have a single, non-intersecting boundary. No two adjacent sides must be parallel. 

      Johnny has several sticks of various lengths. He would like to construct a rectangular polygon. He is planning to use sticks as horizontal edges of the polygon, and draw vertical edges with a pen. 

      Now Johnny wonders, how many sticks he can use. Help him, find the maximal number of sticks that Johnny can use. He will use sticks only as horizontal edges.

Input
      The first line of the input file contains n — the number of sticks (1 ≤ n ≤ 100). The second line contains n integer numbers — the lengths of the sticks he has. The length of each stick doesn’t exceed 200.
Output
      Print l — the number of sticks Johnny can use at the first line of the output file. The following 2l lines must contain the vertices of the rectangular polygon Johnny can construct. Vertices must be listed in order of traversal. The first two vertices must be the ends of a horizontal edge. If there are several solution, output any one. Vertex coordinates must not exceed 10 9
.      If no polygon can be constructed, output l = 0.
Sample Input
4
1 2 3 5
4
1 2 4 8
4
1 1 1 1
Sample Output
3
0 0
1 0
1 1
3 1
3 2
0 2
0
4
0 0
1 0
1 1
2 1
2 -2
1 -2
1 -1
0 -1
Hint

单组数据

      In the first example Johnny uses a stick of length 1 for (0, 0)−(1, 0) edge, a stick of length 2 for (1, 1)−(3, 1) edge and a stick of length 3 for (3, 2) − (0, 2) edge. There is no way to use all four sticks.

Source
Andrew Stankevich Contest 23
Manager

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

动规~

做了两天的题,思路不难,但是写起来很麻烦……而且最后还要求输出组成最大值的边的位置,一脸懵啊……方法还真是神奇,用了一个fa数组记录前继边的长度,最后用l和r递推输出~

其实题目就相当于是用小木棍拼成两条长度相等的边使得它们最长,用f[i][j]表示已用i根木棍,上下差值为j的最大长度,C++要再加上20000(100*200)防止下表出现负数。

数组开小了循环总是莫名其妙地终止……后来才发现真是纠结啊……


#include<cstdio>
#include<cstring>

int n,a[101],f[101][40001],ans1[101],ans2[101],l,r,fa[101][40001],now;

int main()
{
	while(scanf("%d",&n)==1)
	{
		memset(f,-1,sizeof(f));f[0][20000]=0;
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		l=r=20000;
		for(int i=1;i<=n;i++)
		{
			for(int j=l;j<=r;j++)
			{
				if(f[i-1][j]<=-1) continue;
				if(f[i][j]<f[i-1][j])
				{
					f[i][j]=f[i-1][j];fa[i][j]=j;
				}
				if(f[i][j+a[i]]<f[i-1][j]+1)
				{
					f[i][j+a[i]]=f[i-1][j]+1;fa[i][j+a[i]]=j;
				}
				if(f[i][j-a[i]]<f[i-1][j]+1)
				{
					f[i][j-a[i]]=f[i-1][j]+1;fa[i][j-a[i]]=j;
				}
			}
			l-=a[i];r+=a[i];
		}
		printf("%d\n",f[n][20000]);
		now=20000;ans1[0]=ans2[0]=0;
		for(int i=n;i>=1;i--)
		{
			int k=fa[i][now];
			if(k<now) ans1[++ans1[0]]=now-k;
			if(k>now) ans2[++ans2[0]]=k-now;
			now=k;
		}
		l=r=0;
		for(int i=1;i<=ans2[0];i++)
		{
			r++;
			printf("%d %d\n",l,r);
			l+=ans2[i];
			printf("%d %d\n",l,r);
		}
		r=0;
		for(int i=1;i<=ans1[0];i++)
		{
			r--;
			printf("%d %d\n",l,r);
			l-=ans1[i];
			printf("%d %d\n",l,r);
		}
	}
	return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值