P5928 [国家集训队] 文学 题解
Description
给定
求最小的总价格。
Solution
此解法为
同时不需要对半平面做任何操作,也不需要对关键点做分类,或作出一个新的坐标系。
在纸上画一些半平面后容易发现,半平面未覆盖的区域为一个凸包或凸壳,由于凸包和凸壳没有本质区别,为方便表述,下文以凸包为例。
同时我们还发现,最优情况下所有半平面都限制凸包,如图。
因为一个半平面若不限制凸包可以直接不选,减少花费。
用一条平行于
对于关键点而言,只要此时限制凸包的两个半平面能覆盖它就是合法的,否则要再添加一个半平面来覆盖它。
容易想到用动态规划来进行此操作。
设
初始化将
边界为
设
依照上文操作得出转移方程:
那么答案就为
为什么此方程不会选择同一个半平面多次呢?
因为若
记得没有满足条件的选择方案时,输出 -1。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,p;
int a[110],b[110],c[110],w[110];
int dp[110][110][110];
struct node{
int x,y;
}t[110];
bool cmp(node x,node y){
return x.x<y.x;
}
bool check(int x,int y){
if(a[y]*t[x].x+b[y]*t[x].y<=c[y]) return 1;
return 0;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>p;
a[0]=b[0]=0,c[0]=-1e9,w[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i]>>c[i]>>w[i];
}
for(int i=1;i<=p;i++){
cin>>t[i].x>>t[i].y;
}
sort(t+1,t+1+p,cmp);
for(int i=0;i<=p;i++){
for(int j=0;j<n;j++){
for(int k=j+1;k<=n;k++){
dp[i][j][k]=1e9;
}
}
}
for(int i=0;i<n;i++){
for(int j=i+1;j<=n;j++){
dp[0][i][j]=w[i]+w[j];
}
}
for(int i=1;i<=p;i++){
for(int j=0;j<n;j++){
for(int k=j+1;k<=n;k++){
if(dp[i-1][j][k]==1e9) continue;
if(check(i,j)||check(i,k)){
dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]);
continue;
}
for(int l=1;l<=n;l++){
if(l==j||l==k||!check(i,l)) continue;
dp[i][min(l,j)][max(l,j)]=min(dp[i][min(l,j)][max(l,j)],dp[i-1][j][k]+w[l]);
dp[i][min(l,k)][max(l,k)]=min(dp[i][min(l,k)][max(l,k)],dp[i-1][j][k]+w[l]);
}
}
}
}
int ans=1e9;
for(int i=0;i<n;i++){
for(int j=i+1;j<=n;j++){
ans=min(ans,dp[p][i][j]);
}
}
cout<<(ans==1e9?-1:ans);
return 0;
}