题目链接
学习了大佬博客
难度比较大,需要枚举很多种情况,对思维的全面性要求高
#include<iostream>
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int xn,yyn,xt,yt,n;
//壁龛的宽度高度、旧书的宽度和高度、货架的数量
int mindz=INF,minmb=INF;//最少钉子,最少木板
struct node{
int x,y,l,x1,x2;
//左端距离、高度、长度、左端和左支撑钉距离、左端和右支撑点的距离
friend bool operator <(node a,node b){
return a.y<b.y;//重载小于号,用来排序
}
}p[105];
void move(int k,int x,int &dz,int &mb)
{
for(int i=k+1;i<=n;i++)//木板是有序的,故在枚举完在第k个木板上放书后,要判断k以上的木板是否会阻挡书的放置
{
if(p[i].y>=p[k].y+yt)break;//以上的都挨不到书了
if(p[i].x+p[i].l<=x||p[i].x>x+xt)continue;//此木板不会对书架造成影响
if(p[i].x2<=x)//此木板右钉子在起始点左端
{
int lst;//注意,可以通过左移来避免对书架造成影响
if(x<=2*p[i].x1)//要考虑重心的问题
lst=2*(x-p[i].x1);
else
lst=x;
if(lst<p[i].l)mb+=p[i].l-lst;
}
else if(p[i].x1>=x+xt)//木板左钉子在终点的右端
{
int lst;//与上种情况同理
if(p[i].x2-x-xt<=xn-p[i].x2)
lst=2*(p[i].x2-x-xt);
else lst=xn-x-xt;
if(lst<p[i].l)mb+=p[i].l-lst;
}
else if(p[i].x1<=x&&p[i].x2>x&&p[i].x2<x+xt)//起始点钉子在钉子之间且终点在右钉子右边
{
if(x==0)//若起始点为0,只能删掉一整条边
{
dz+=2;
mb+=p[i].l;
}
else//移钉
{//注意:对于此情况,是将木板靠到最左边,最右的部分截掉
dz++;
if(p[i].l>x)mb+=p[i].l-x;//截木板
}
}
else if(p[i].x1>x&&p[i].x1<x+xt&&p[i].x2>=x+xt)//左钉子在起始点与终点之间并且右钉子在终点的右端
{
if(x+xt==xn)//若终点到右端了,只能删除一整条边
{
dz+=2;
mb+=p[i].l;
}
else//移钉
{//注意:对于此情况,是将木板靠到最右边,最左的部分截掉
dz++;
if(p[i].l>xn-x-xt)mb+=p[i].l-xn+x+xt;//截木板
}
}
else if(p[i].x1<=x&&p[i].x2>=x+xt)//两钉子在起点终点的两端之外
{
if(x==0&&xt==xn)//只能全拆掉
dz+=2;
else dz++;
int lst=max(x,xn-x-xt);
if(p[i].l>lst)
mb+=p[i].l-lst;
}
else if(p[i].x1>x&&p[i].x2<x+xt)//不多想直接拆
{
dz+=2;
mb+=p[i].l;
}
}
}
void solve(int k)
{
for(int i=0;i<=xn-xt;i++)//枚举书的起始位置
{
int dz=0,mb=0;
if(i+p[k].l<p[k].x1)continue;//木板根本放不到钉子上,continue
if(2*(p[k].x1-i)>p[k].l||//重心出界(左钉子)
2*(i+xt-p[k].x2)>p[k].l||//重心出界(右钉子)
p[k].x2-i>p[k].l||//木板长度不够(左端点到右钉子距离超过了木板长度)
i+xt-p[k].x1>p[k].l)//木板长度不够(右端点到左钉子距离超过了木板长度)
dz++;
move(k,i,dz,mb);
if(dz<mindz||(dz==mindz&&mb<minmb))
mindz=dz,minmb=mb;
}
}
int main()
{
#ifdef local
freopen("in.txt","r",stdin);
#endif
scanf("%d%d%d%d",&xn,&yyn,&xt,&yt);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d%d",&p[i].y,&p[i].x,&p[i].l,&p[i].x1,&p[i].x2);
p[i].x1+=p[i].x; //左墙与最左端钉子
p[i].x2+=p[i].x;//左墙与最右端钉子
}
sort(p+1,p+n+1);//按照书架的高度从低到高排序
for(int i=1;i<=n;i++)
{
if(p[i].y+yt>yyn)break;//若第i个书架的高度加上书的高度大于最大高度
//书无法放在i以后的任何一个书架上,直接break
if(p[i].l>=xt)solve(i);
//若第i个书架可以放得下最大的那本书,则开始找其最小耗费
}
printf("%d %d",mindz,minmb);
return 0;
}