1. 程式人生 > >bzoj 1390: [Ceoi2008]Fence

bzoj 1390: [Ceoi2008]Fence

最小環 char input out rip 保護 bre %d des

Description

在一個大小為1000*1000的區域中,有n個固定點,m棵tree 。 現在你要建一個圍欄來保護tree,建它的費用為你選用的固定點的個數 *20和 你沒有圈進圍欄的tree*111. 現在希望這個值越小越好. 3<=N<=100. 1<=M<=100

Input

第一行給出n,m 下面開始n行,給出固定的坐標 下面開始m行,給出tree的坐標

Output

輸出最小費用

根據題目設定的參數,凡是可以圍住的點都要圍住,同bzoj1027可以轉為最小環

#include<bits/stdc++.h>
struct pos{
    int
x,y; void read(){ scanf("%d%d",&x,&y); } }ns[107],ms[107],cs[107]; pos operator-(pos a,pos b){return (pos){a.x-b.x,a.y-b.y};} int operator*(pos a,pos b){return a.x*b.y-a.y*b.x;} bool operator<(pos a,pos b){return a*b<0;} int ans=0,n,m,cp=0; bool in(pos w){ for(int
i=2;i<cp;++i)if(cs[i-1]<w&&w<cs[i]){ return cs[i-1]-w<cs[i]-w; } return 0; } void mins(int&a,int b){if(a>b)a=b;} int l[107][107]; char s[107][107]; int main(){ scanf("%d%d",&n,&m); for(int i=0;i<n;++i)ns[i].read(); for(int i=0;i<m;++i)ms[i].read();
for(int i=1;i<n;++i)if(ns[i].x<ns[0].x)std::swap(ns[i],ns[0]); pos p0=ns[0]; for(int i=0;i<n;++i)ns[i]=ns[i]-p0; for(int i=0;i<m;++i)ms[i]=ms[i]-p0; std::sort(ns+1,ns+n); for(int i=0;i<n;++i){ while(cp>=2&&ns[i]-cs[cp-1]<cs[cp-1]-cs[cp-2])--cp; cs[cp++]=ns[i]; } int p=0; for(int i=0;i<m;++i){ if(!in(ms[i]))ans+=111; else ms[p++]=ms[i]; } m=p; if(p){ for(int i=0;i<n;++i){ for(int j=0;j<n;++j){ l[i][j]=0x3f3f3f3f; if(i!=j){ bool is=1; pos d=ns[i]-ns[j]; for(int k=0;k<m;++k)if(d<ms[k]-ns[j]){ is=0; break; } if(is)l[i][j]=1; } } } for(int k=0;k<n;++k) for(int i=0;i<n;++i) for(int j=0;j<n;++j)mins(l[i][j],l[i][k]+l[k][j]); for(int i=1;i<n;++i)mins(l[0][0],l[i][i]); ans+=l[0][0]*20; } printf("%d\n",ans); return 0; }

bzoj 1390: [Ceoi2008]Fence