题目描述
给定一个具有N(N<50)个顶点(从1到N编号)的凸多边形,每个顶点的权均已知。问如何把这个凸多边形划分成N-2个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小?这应该怎么计算呢?
输入
第一行为顶点数N,第二行为 N个顶点(从1到N)的权值。
输出
第一行为最小的和的值。
第二行为各三角形组成的方式。各三角形各顶点之间以空格间隔,顶点从小到大排序,三角形之间从左到右按字典序排序,中间的逗号为半角字符。
样例输入
5
121 122 123 245 231
样例输出
12214884
1 2 3,1 3 5,3 4 5
剖分问题,找最后一个决策点就行了,注意要输出方案。
设dp[i][j]表示从i到j进行三角形划分能得到的最大值,显然有dp[i][j]=max(dp[i][j],dp[i][k]+dp[k][j]+val[i]*val[j]*val[k])枚举分割点k,时间复杂度O(n^3).
注意写高精度!!!
上代码。
1 #include<bits/stdc++.h> 2 #define mod 10000 3 #define maxn 305 4 #define N 105 5 using namespace std; 6 struct HP { 7 int len; 8 long long p[maxn]; 9 HP &operator = (const char *); 10 HP &operator = (long long); 11 HP(){memset(p,0,sizeof(p));len=1;} 12 HP(long long); 13 14 bool operator >(const HP &) const; 15 bool operator <(const HP &) const; 16 bool operator <=(const HP &) const; 17 bool operator >=(const HP &) const; 18 bool operator !=(const HP &) const; 19 bool operator ==(const HP &) const; 20 21 HP operator + (const HP &) const; 22 HP operator - (const HP &) const; 23 HP operator * (const HP &) const; 24 HP operator / (const HP &) const; 25 HP operator % (const HP &) const; 26 27 HP &operator +=(const HP &); 28 HP &operator -=(const HP &); 29 HP &operator *=(const HP &); 30 HP &operator /=(const HP &); 31 HP &operator %=(const HP &); 32 }; 33 HP & HP::operator = (const char *str) { 34 memset(p,0,sizeof(p)); 35 int n=strlen(str),j=1,k=1; 36 for(int i=1;i<=n;i++){ 37 if(k==mod) j++,k=1; 38 p[j]+=k*(str[n-i]-'0'); 39 k*=10; 40 } 41 len=j; 42 return *this; 43 } 44 HP & HP::operator = (long long num) { 45 char s[101]; 46 sprintf(s,"%d",num); 47 return *this=s; 48 } 49 HP::HP(long long num) {*this=num;} 50 bool HP::operator <(const HP &a)const { 51 if(len<a.len) return 1; 52 else if(len>a.len) return 0; 53 else { 54 int i=len; 55 while(i>=1) { 56 if(p[i]<a.p[i]) return 1; 57 else if(p[i]>a.p[i]) return 0; 58 else i--; 59 } 60 return 0; 61 } 62 } 63 bool HP::operator >(const HP &b) const {return b<*this;} 64 bool HP::operator <=(const HP &b) const {return !(*this>b);} 65 bool HP::operator >=(const HP &b) const {return !(*this<b);} 66 bool HP::operator !=(const HP &b) const {return (b<*this)||(*this<b);} 67 bool HP::operator ==(const HP &b) const {return !(*this<b)&&!(b<*this);} 68 69 HP HP::operator + (const HP &b)const { 70 HP c; 71 c.len=len>b.len?len:b.len; 72 int i=1; 73 while(i<=c.len) { 74 c.p[i]+=p[i]+b.p[i]; 75 if(c.p[i]>=mod) { 76 c.p[i+1]++,c.p[i]-=mod; 77 } 78 i++; 79 } 80 if(c.p[c.len+1]>0) c.len++; 81 return c; 82 } 83 HP HP::operator -(const HP &b)const{ //a-b 84 HP c; 85 c.len=len; 86 for(int i=1; i<=c.len; i++) { 87 c.p[i]+=p[i]-b.p[i]; 88 if(c.p[i]<0) { 89 c.p[i]+=mod; 90 c.p[i+1]--; 91 } 92 } 93 while(c.p[c.len]==0&&c.len>1) c.len--; 94 return c; 95 } 96 HP &HP::operator +=(const HP &b) {return *this=*this+b;} 97 HP &HP::operator -=(const HP &b) {return *this=*this-b;} 98 HP HP::operator *(const HP &b)const{ 99 HP c; 100 int i=1,j=1,k=1; 101 c.len=len+b.len+1; 102 while(i<=len) { 103 k=i; 104 j=1; 105 while(j<=b.len) { 106 c.p[k]+=p[i]*b.p[j]; 107 if(c.p[k]>=mod) {c.p[k+1]+=c.p[k]/mod,c.p[k]%=mod;} 108 k++,j++; 109 } 110 i++; 111 } 112 while(c.p[c.len]==0&&c.len>1) c.len--; 113 return c; 114 } 115 HP &HP::operator *=(const HP &b){return *this=*this*b;} 116 HP HP::operator /(const HP &b)const { // a/b 117 HP c,d; 118 c.len=len; 119 d.len=0; 120 for(int i=len; i>=1; i--) { 121 d=d*HP(mod)+p[i]; 122 long long left=0,right=9999,mid; 123 while(left<right) { 124 mid=(left+right)/2; 125 if(b*HP(mid)<=d) left=mid+1; 126 else right=mid; 127 } 128 long long ans1=right-1; 129 long long ans2=right; 130 if(HP(ans2)*b<=d) ans1=ans2; 131 c.p[i]=ans1; 132 d=d-b*HP(ans1); 133 } 134 while(c.p[c.len]==0&&c.len>1) c.len--; 135 return c; 136 } 137 HP HP::operator %(const HP &b)const { 138 HP c,d; 139 c.len=len+b.len+1; 140 d.len=0; 141 for(int i=len; i>=1; i--) { 142 d=d*HP(mod)+p[i]; 143 long long left=0,right=9999,mid; 144 while(left<right) { 145 mid=(left+right)/2; 146 if(b*HP(mid)<=d) left=mid+1; 147 else right=mid; 148 } 149 long long ans1=right-1; 150 long long ans2=right; 151 if(HP(ans2)*b<=d) ans1=ans2; 152 c.p[i]=ans1; 153 d=d-b*HP(ans1); 154 } 155 while(c.p[c.len]==0&&c.len>1) c.len--; 156 return d; 157 } 158 HP &HP::operator /=(const HP &b){*this=*this/b;} 159 HP &HP::operator %=(const HP &b){*this=*this%b;} 160 ostream & operator << (ostream &o,HP &n) { 161 o<<n.p[n.len]; 162 for(int i=n.len-1; i>=1; i--) { 163 o.width(4); 164 o.fill('0'); 165 o<<n.p[i]; 166 } 167 return o; 168 } 169 istream & operator >> (istream & in,HP &n) { 170 char s[maxn]; 171 in>>s; 172 n=s; 173 return in; 174 } 175 //前面是高精度模板 176 177 HP s[N];//保存节点的数组也要有高精度!!之前一直没注意,两个点一直WA 178 HP dp[N][N]; 179 struct ANS{ 180 int x,y,z; 181 bool operator <(const ANS&t)const{ 182 if(x!=t.x) return x<t.x; 183 if(y!=t.y) return y<t.y; 184 if(z!=t.z) return z<t.z; 185 } 186 }res[N];//res数组保存的是我们最终的分解方案 187 int ans[N][N];//ans[i][j]表示将i节点,j节点,ans[i][j]节点划分为一个三角形 188 int ct; 189 inline void dfs(int x,int z){ 190 if(ans[x][z]==0) return ; 191 res[++ct].x=x,res[ct].y=ans[x][z],res[ct].z=z; 192 dfs(x,ans[x][z]),dfs(ans[x][z],z); 193 }//递归求解方案。 194 int n; 195 int main(){ 196 scanf("%d",&n); 197 for(register int i=1;i<=n;i++) cin>>s[i]; 198 for(register int i=n;i>=1;i--){ 199 for(register int j=i+1;j<=n;j++){ 200 for(register int k=i+1;k<j;k++){ 201 if(i==j||i==k||j==k) continue; 202 HP c=dp[i][k]+dp[k][j]+s[i]*s[j]*s[k]; 203 //从i到k进行划分的值加上从k到j划分的值再加上i,j,k划分为一个三角形的值 204 if(dp[i][j].len==1&&dp[i][j].p[1]==0) dp[i][j]=c,ans[i][j]=k;//如果当前状态未被更新,则更新 205 else if(dp[i][j]>c){ 206 dp[i][j]=c; 207 ans[i][j]=k;//记录方案 208 } 209 } 210 } 211 } 212 dfs(1,n); 213 sort(res+1,res+1+ct); 214 cout<<dp[1][n]; 215 if(dp[1][n].len==1&&dp[1][n].p[1]==0) return 0;//没有用的判断。。。 216 printf("\n"); 217 for(register int i=1;i<ct;i++){ 218 printf("%d %d %d,",res[i].x,res[i].y,res[i].z); 219 } 220 printf("%d %d %d",res[ct].x,res[ct].y,res[ct].z);//完结撒花 221 return 0; 222 }