ACdream 1429 Rectangular Polygon
Time Limit: 1000MS | Memory Limit: 256000KB | 64bit IO Format: %lld & %llu |
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
Output
. 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
第一问:求最多使用木棍数量。竖边可以无视,问题简化成从所有木棍中挑出一部分,分成总长度相等的两组,求最大总长度。动规可解。
第二问:具体摆法。由于是多解任意输出一解,竖边依旧可以无视。在之前的动规中保存一下每次用的木棍长度(我保存的是端点间相对位置),最后输出就行。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 const int q=1000000007; 7 const int mxn=120; 8 const int bas=20400; 9 int le,ri; 10 int a[mxn]; 11 int dp[mxn][bas*2],p[mxn][bas*2]; 12 int n; 13 int st1[mxn],tp1; 14 int st2[mxn],tp2; 15 16 int main(){ 17 while(scanf("%d",&n)!=EOF){ 18 memset(dp,-1,sizeof(dp)); 19 memset(p,0,sizeof(p)); 20 int i,j; 21 le=ri=bas; 22 for(i=1;i<=n;i++)scanf("%d",&a[i]); 23 dp[0][bas]=0; 24 p[1][bas]=bas; 25 for(i=1;i<=n;i++){ 26 for(j=le;j<=ri;j++){//枚举长度差 27 if(dp[i-1][j]<=-1)continue; 28 if(dp[i][j]<dp[i-1][j]){ 29 dp[i][j]=dp[i-1][j];//不选 30 p[i][j]=j; 31 } 32 if(dp[i][j+a[i]]<dp[i-1][j]+1)//放在上面 33 { 34 dp[i][j+a[i]]=dp[i-1][j]+1; 35 p[i][j+a[i]]=j; 36 } 37 if(dp[i][j-a[i]]<dp[i-1][j]+1)//放在下面 38 { 39 dp[i][j-a[i]]=dp[i-1][j]+1; 40 p[i][j-a[i]]=j; 41 } 42 } 43 le-=a[i];//扩展规划范围 44 ri+=a[i]; 45 } 46 printf("%d\n",dp[n][bas]);//回答第一问:最多使用木棍数量 47 int tnow=bas;//最终端点位置 48 int tmp; 49 tp1=0;tp2=0; 50 for(i=n;i>=1;i--){//倒着找 51 tmp=p[i][tnow];//上次木棍端点位置 52 // printf("test: %d %d\n",tmp,tnow); 53 if(tmp>tnow)st2[++tp2]=tmp-tnow; 54 if(tmp<tnow)st1[++tp1]=tnow-tmp; 55 tnow=tmp;//更新位置 56 } 57 int x=0,y=0; 58 while(tp2) 59 { 60 y++; 61 printf("%d %d\n",x,y); 62 x+=st2[tp2]; 63 printf("%d %d\n",x,y); 64 tp2--; 65 } 66 while(tp1) 67 { 68 y++; 69 printf("%d %d\n",x,y); 70 x-=st1[tp1]; 71 printf("%d %d\n",x,y); 72 tp1--; 73 } 74 } 75 return 0; 76 }