bzoj3822: 文學

Description

巨醬和主席是一對好朋友。他們都很喜歡讀書,常常一塊兒閱讀相關領域書籍,進行系統的學習。一天主席列出了一份列表,裏面共 p 本書,其中不乏《約翰克里斯多夫》,《名人傳》等名著。做爲一名在文學上有很高修養的知名青年,巨醬打算用盡可能少的時間把這份列表中的全部書籍都讀完。
做爲一名文化人,巨醬閱讀書籍的方式也與通常人不一樣。他使用一種叫作「批量閱讀」的閱讀方式。首先他根據本身的喜愛,對每本書給出了個參數 x,y,其中 i 本書的兩個參數爲 xi,yi。固然,因爲巨醬獨特的口味,可能有兩本不一樣的書,它們的 x、y 參數均相同。而每次閱讀的時候,他會設置三個係數 a, b, c,全部知足 ax+by≤c 的書籍均可以經過此次「批量閱讀」讀完,此次批量閱讀總共須要 w 的時間。
如今,巨醬有 n 種 「批量閱讀」的方案,第 i 種「批量閱讀」三個參數爲 ai,bi,ci,須要的時間爲 wi。如今巨醬打算從這 n 種「批量閱讀」中選出若干,使得巨醬能夠用盡可能少的時間讀完全部的書。如今咱們想知道,巨醬最少用多少時間?

Input

第一行兩個正整數 n,p,分別表示「批量閱讀」的方案數以及書的數量。
接下來 n 行,每行四個整數,其中第 i 行包含四個整數 ai,bi,ci,wi,表示第 i 種「批量閱讀」的方案。
接下來 p 行,每行兩個整數,其中第 i 行包含兩個整數 xi,yi,表示第 i 本書的參數。

Output

一行一個整數,表示最少須要的時間。若不管如何也沒法讀徹底部書籍,則輸出 −1。

每本書看做平面上一點,每一個方案則爲一個半平面,轉化爲求最小權值和的 半平面並 覆蓋全部點。學習

首先能夠特判掉一個半平面覆蓋全部點的狀況,其他狀況的解至少有兩個半平面,那麼能夠枚舉其中的兩個半平面,以半平面的交點爲中心對其他未被覆蓋的點進行極角排序spa

能夠發現存在一種劃分貢獻的方式,使排序後的點被劃分爲幾個連續段,每段被解中的某個半平面覆蓋,因而能夠區間dp,總複雜度是O(n4)code

在斷定點在半平面內時,計算結果在1012內,且計算結果和原數值都爲整數,用double能夠精確表示和計算blog

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
const int inf=0x3f3f3f3f;
int n,m;
struct hp{
    double a,b,c;int v;
    void read(){scanf("%lf%lf%lf%d",&a,&b,&c,&v);}
}h[103];
struct pos{
    double x,y;
    void read(){scanf("%lf%lf",&x,&y);}
    bool in(hp w){return x*w.a+y*w.b<=w.c;}
    pos operator-(pos w){return (pos){x-w.x,y-w.y};}
    double operator*(pos w){return x*w.y-y*w.x;}
}p[103],s[103];
pos p0;
bool operator<(pos a,pos b){
    return (a-p0)*(b-p0)<0;
}
pos cross(hp x,hp y){
    double v=x.a*y.b-y.a*x.b;
    return (pos){(x.c*y.b-y.c*x.b)/v,(x.c*y.a-y.c*x.a)/-v};
}
int f[103],g[103][103],sp=0,ans=inf;
void mins(int&a,int b){if(a>b)a=b;}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)h[i].read();
    for(int i=1;i<=m;++i)p[i].read();
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j)if(!p[j].in(h[i]))goto o;
        mins(ans,h[i].v);o:;
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<i;++j){
            sp=0;
            p0=cross(h[i],h[j]);
            for(int k=1;k<=m;++k)if(!(p[k].in(h[i])||p[k].in(h[j])))s[++sp]=p[k];
            std::sort(s+1,s+sp+1);
            memset(f,0x3f,sizeof f);
            memset(g,0x3f,sizeof g);
            for(int a=1;a<=n;++a)if(a!=i&&a!=j){
                for(int l=1,r;l<=sp;++l){
                    if(!s[l].in(h[a]))continue;
                    for(r=l;r<sp&&s[r+1].in(h[a]);++r);
                    mins(g[l][r],h[a].v);
                    l=r+1;
                }
            }
            for(int d=sp;d>1;--d)for(int l=1,r=d;r<=sp;++l,++r)mins(g[l][r-1],g[l][r]),mins(g[l+1][r],g[l][r]);
            f[0]=0;
            for(int b=1;b<=sp;++b)for(int a=0;a<b;++a)mins(f[b],f[a]+g[a+1][b]);
            mins(ans,f[sp]+h[i].v+h[j].v);
        }
    }
    printf("%d",ans==inf?-1:ans);
    return 0;
}
相關文章
相關標籤/搜索