# Problem G. Rectangular Polygon(dp + 转移重现）

#### 2006-2007 Winter Petrozavodsk Camp, Andrew Stankevich Contest 23 (ASC 23)

Problem G. Rectangular Polygon
Input file: polygon.in
Output file: polygon.out
Time limit: 1 second
Memory limit: 64 megabytes
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 109
.
If no polygon can be constructed, output l = 0.
Example
polygon.in polygon.out
4
1 2 3 5
3
0 0
1 0
1 1
3 1
3 2
0 2
4
1 2 4 8
0
4
1 1 1 1
4
0 0
1 0
1 1
2 1
2 -2
1 -2
1 -1
0 -1
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.

#include<bits/stdc++.h>
using namespace std;

const int maxn = 4e4 + 5;

struct X{
int pre;     当前的状态时由上一个哪个状态转移来的
int sum;
}dp[105][maxn];  dp[i][j].sum : 前 i 个砝码，偏移度为 j 最多拿多少个砝码。

若左边秤更重时 j（向左偏移 j 重量)就为负数，若右边秤更重时j（向左偏移 j 重量)为正数，
若天平平衡时 j 为0。

因为数组的 j 不能为负数，所以就整体向右平移20000，天平平衡时 j 为20000。

因为n最大为100，每个砝码最大为200，如果都放在左边 j 就为-20000。

所以最后答案为：dp[n][20000];

int w[105];      砝码的重量。
int l[105];      放左边砝码的重量。
int r[105];      放右边砝码的重量。

void Init(int n){初始化
for(int i = 0;i <= n;i++){
for(int j = 0;j <= 40000;j++){
dp[i][j].sum = -100000000;
}
}
dp[0][20000].sum = 0;
}

int main(){
freopen("polygon.in","r",stdin);
freopen("polygon.out","w",stdout);
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%d",&w[i]);
Init(n);
for(int i = 1;i <= n;i++){
for(int j = 0;j <= 40000;j++){
if(j >= w[i] && j + w[i] <= 40000){
int a,b,c,M;
a = dp[i - 1][j - w[i]].sum + 1;//第 i 个砝码放右边。
b = dp[i - 1][j + w[i]].sum + 1;//第 i 个砝码放左边。
c = dp[i - 1][j].sum;           //第 i 个砝码不放。
M = max(a,max(b,c));
if(M == a) dp[i][j].pre = j - w[i];
else if(M == b) dp[i][j].pre = j + w[i];
else if(M == c) dp[i][j].pre = j;
dp[i][j].sum = M;
}
else if(j >= w[i]){
int a,b,M;
a = dp[i - 1][j - w[i]].sum + 1;//第 i 个砝码放右边。
b = dp[i - 1][j].sum;           //第 i 个砝码不放。
M = max(a,b);
if(M == a) dp[i][j].pre = j - w[i];
else if(M == b) dp[i][j].pre = j;
dp[i][j].sum = M;
}
else if(j + w[i] <= 40000){
int a,b,M;
a = dp[i - 1][j + w[i]].sum + 1;//第 i 个砝码放右边。
b = dp[i - 1][j].sum;           //第 i 个砝码不放。
M = max(a,b);
if(M == a) dp[i][j].pre = j + w[i];
else if(M == b) dp[i][j].pre = j;
dp[i][j].sum = M;
}
else{
dp[i][j].sum = dp[i - 1][j].sum;//第 i 个砝码不放。
dp[i][j].pre = j;
}
}
}

int ll = 0,rr = 0,tot = 20000;//把左右边秤的砝码挑出来。
for(int i = n;i >= 1;i--){
int ans = dp[i][tot].pre - tot;
if(ans > 0) l[++ll] = ans;
else if(ans < 0) r[++rr] = -ans;
tot = dp[i][tot].pre;
}

printf("%d\n",dp[n][20000].sum);
if(dp[n][20000].sum != 0){//选的砝码的个数不为0就输出。
int x,y;
x = l[1],y = 0;
printf("0 0\n");
printf("%d %d\n",x,y);
for(int i = 2;i <= ll;i++){
y++;
printf("%d %d\n",x,y);
x += l[i];
printf("%d %d\n",x,y);
}
y++;
printf("%d %d\n",x,y);
x -= r[1];
printf("%d %d\n",x,y);
for(int i = 2;i <= rr;i++){
y++;
printf("%d %d\n",x,y);
x -= r[i];
printf("%d %d\n",x,y);
}
}
}

• 本文已收录于以下专栏：

举报原因： 您举报文章：Problem G. Rectangular Polygon(dp + 转移重现） 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)