话说,我已经很久没有写博客了,其实里面有很大一段的故事的。。。
不管了,现在都已经11号了,还有7天考试,真是着实不爽啊!
好了,回到正题了,这周我们练了一个合并类的动态规划:
0多边形【推荐】
1 【NOIP动态规划专题】等腰三角形
2 【NOIP动态规划专题】能量项链
3 行政划分【难】
0 多边形【推荐】
多边形是一个单人玩的游戏,开始时有一个N个顶点的多边形。如图,这里N=4。每个顶点有一个整数标记,每条边上有一个“+”号或“*”号。边从1编号到N。
第一步,一条边被拿走;随后各步包括如下:
选择一条边E和连接着E的两个顶点V1和 V2;
得到一个新的顶点,标记为V1与V2通过边E上的运算符运算的结果。
最后,游戏中没有边,游戏的得分为仅剩余的一个顶点的值。
写一个程序,对于给定一个多边形,计算出可能的最高得分以及操作方法。
【数据范围】
3<=N<=50
不管怎么操作,中间结果一定在[-32768,32767]范围内。
分析
好了对于这题,我们可以先枚举一条被删的边,然后我们就可以把这个多边形展开
这是很重要的思想:一个图形很难dp,而把它变成一列点便变得很好dp了。
于是我们设f[i,j]表示已经计算出第i个点到第j个点的操作最大值,
明显的f[i,j]=max(f[i,k]&f[k,j])&表示计算的符号。
那么这样就完成了吗?很明显的不是,因为这题里面有负数!
有负数就意味着两个负数的积有可能超过两个正数的积,所以在这里我们再设:
g[i,j]表示最小的值。
转移都差不多的。
【NOIP动态规划专题】等腰三角形
给定一个正N边形,可以通过连线将这个多边形分割成N-2个三角形,问这N-2个三角形中恰有k个等腰三角形的分割方法有多少?这个值可能很大,输出对9397取模的结果。
分析
其实上面的题目就是这题的基础,我们也一样把点都展开来,那么方程应该是:
f[i,j,k]表示i到j的点形成k个等腰三角形的方案数。
f[i,j,k]=∑l<jl=i+1∑r<=kr=0f[i,l,r]∗f[l,j,k−r−pd()]
这里的方程和上面唯一不一样的是减了一个pd(),这个是指有可能l和i和j的连线会形成一个等腰三角形。
而情况请读者自己考虑。
【NOIP动态规划专题】能量项链
比较水,不讲了。
行政划分【难】
这题是重点!
某国领土形状十分奇特,可以将它近似地看作是一个有N 个顶点的凸多边形 。现在该国政府想要将它划分为(N-2)个互不重叠的行政区域,并希望每个区域的形状都是三角形,三角形的顶点即为凸多边形的顶点。该国政府又出于资源、人口、宗教等多方面的考虑,希
望得到一种划分方案,使得(N-2)块区域的面积的方差最小
现在该国政府官员找到了你,希望你能够帮助他们解决这个问题。
Input
第一行是一个整数N (4≤N≤50), 表示凸多边形顶点的个数
接下来的N 行,每行有两个实数X、Y(-1000000≤X、Y≤1000000),分别表示按比例缩小后的凸多边形顶点在坐标系内的横纵坐标值。
你只要输出一个实数,即最小方差值 (保留到百分位)。
注意:凸多边形的顶点不一定按顺序给出。
分析
我们先不考虑如何求凸边形的面积如何去求,先考虑如何dp。
这题还是多边形,于是我们考虑将其转换为一些点列,类似的:
f[i,j]表示从第i个点到第j个点之间的面积的最小的方差
(之所以它可以dp是因为可以转换成各个三角形之间的决策,而且最后的答案和sqrt()和/(n-2)运算没有关系)
(但这里注意dp时点的顺序是有关系的,所以后面会写如何求点的顺序)
所以,就可以f[i,j]=min(f[i,j],f[i,k]+f[k,j]+sqr(sum(i,k,j)-ave)),
sum(i,j,k)表示的是边长为i,j,k的长度的三角形的面积。用海伦公式求。
ave指多边形的面积/(n-2),即平均值。
那么现在的问题就是如何求凸多边形的面积。
我们会想到划分成三角形的面积,但是如何确定点的顺序呢?
这里介绍一个函数:
atan2(y,x)的值为坐标为(x,y)与(0,0)的连线与x轴的正半轴的夹角x*pi/180.
那么我们是否可以随便确定一个点(x,y),然后求出其他点(x1,y1)的atan2(y1-y,x1-x)值
排个序后是否就是我们点的顺序,dp的顺序呢?
基本思想是这样的,但是:
1.我们选为基准的点必须是y坐标最小的同时还是相同y坐标最小的x坐标最小。
为什么呢,因为这样就不会出现负数的角度,会方便很多(这个自己推吧)
2.而且当多个点与基准点的y坐标相同时,它们的顺序是按照x坐标排的,即这些点的atan2值为0,的时候。
这样就可以保证不会出错了。
代码
0多边形
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=105,maxlongint=2147483647;
int n,a[N*2],f[N][N],g[N][N],b[N],an[N],d[N];
char ch;
int main(){
scanf("%d",&n);
int st=1,en=n,op=0;
for(int i=1;i<=n;i++){
scanf("%c",&ch);
scanf("%c",&ch);
scanf("%d",&a[i]);
if (ch=='t') op=1;else op=0;
b[i]=op;st=i;en=i+1;
}
int ans=-maxlongint;
for(int t=1;t<=n;t++){
int bz=1;
for(int i=t;i<=n;i++,bz++) d[bz]=i;
for(int i=1;i<=t-1;i++,bz++) d[bz]=i;
memset(f,128,sizeof(f));
memset(g,127,sizeof(g));
for(int i=1;i<=n;i++) f[i][i]=g[i][i]=a[d[i]];
for(int i=1;i<=n-1;i++){
for(int st=1;st+i<=n;st++){
for(int j=0;j<i;j++)
if (b[d[st+j+1]])
f[st][st+i]=max(f[st][st+i],f[st][st+j]+f[st+j+1][st+i]),
g[st][st+i]=min(g[st][st+i],g[st][st+j]+g[st+j+1][st+i]);
else
f[st][st+i]=max(max(f[st][st+i],f[st][st+j]*f[st+j+1][st+i]),g[st][st+j]*g[st+j+1][st+i]),
g[st][st+i]=min(min(g[st][st+i],g[st][st+j]*g[st+j+1][st+i]),g[st][st+j]*f[st+j+1][st+i]);
}
}
an[t]=f[1][n];ans=max(ans,an[t]);
}
printf("%d\n",ans);
for(int i=1;i<=n;i++)if (an[i]==ans) printf("%d ",i);
}
等腰三角形
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=55,mo=9397;
int n,m,f[N][N][N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) f[i][i+2][1]=f[i][i+1][0]=1;
for(int len=3;len<=n-1;len++){
for(int i=1;i<=n-len;i++){
for(int k=1;k<=m;k++){
if (i==2&&i+len==5&&k==2)
n=n;
for(int l=i+1;l<i+len;l++){
int op=0;
if (n-(i+len)+i-1==(i+len)-l-1||l-i-1==n-(i+len)+i-1||(i+len-l)==l-i) op=1;
if (((i+len)==n)&&(i==n-l||n-l==len||l==i)) op=1;
for(int r=0;r<=k;r++)
f[i][i+len][k]+=f[i][l][r]*f[l][i+len][k-r-op],f[i][i+len][k]%=mo;
}
}
}
}
printf("%d",f[1][n][m]);
}
能量项链
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
int n,a[N*2],f[N][N];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i],a[i+n+n]=a[i];
n*=2;
for(int i=1;i<=n;i++){
for(int st=1;st+i<=n;st++){
for(int j=0;j<i;j++)
f[st][st+i]=max(f[st][st+i],f[st][st+j]+f[st+j+1][st+i]+a[st]*a[st+j+1]*a[st+i+1]);
}
}
int ans=0;
for(int i=1;i<=n/2;i++)
ans=max(ans,f[i][i+(n/2)-1]);
printf("%d",ans);
}
行政划分
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#define db double
using namespace std;
const int N=55;
int n;
struct xgf{
db x,y,z;
}a[N];
bool cmp(xgf a,xgf b){
return (a.z<b.z||(a.z==b.z&&a.x<b.x));
}
db sqr(db x){
return x*x;
}
db slen(int x,int y){
return sqrt(sqr(a[x].x-a[y].x)+sqr(a[y].y-a[x].y));
}
db sum(db a,db b,db c){
db p=(a+b+c)/2*1.0;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
int main(){
scanf("%d",&n);
db mi=2147483647.0;
db ma=mi;
int k;
for(int i=1;i<=n;i++){
scanf("%lf%lf",&a[i].x,&a[i].y);
if (mi>a[i].y||mi==a[i].y&&ma>a[i].x) mi=a[i].y,ma=a[i].x,k=i;
}
for(int i=1;i<=n;i++)
if (i!=k)a[i].z=atan2(a[i].y-a[k].y,a[i].x-a[k].x);
sort(a+1,a+n+1,cmp);
db s=0;
for(int i=3;i<=n;i++){
s+=sum(slen(1,i),slen(1,i-1),slen(i,i-1));
}
s=s/(n-2)*1.0;
db f[N][N];
memset(f,127,sizeof(f));
for(int i=1;i<=n-2;i++) f[i][i+2]=sqr(sum(slen(i,i+1),slen(i,i+2),slen(i+1,i+2))-s);
for(int i=1;i<=n;i++) f[i][i+1]=0;
for(int len=1;len<=n-1;len++){
for(int i=1;i<=n-len;i++){
for(int j=i+1;j<i+len;j++){
f[i][i+len]=min(f[i][i+len],f[i][j]+f[j][i+len]+
sqr(sum(slen(i,j),slen(i,i+len),slen(j,i+len))-s));
}
}
}
printf("%.2lf",sqrt(f[1][n]/(n-2)*1.0));
}