立命館合宿2012 day3 問題G (AOJ 2368)
制約条件
n≦50
wi≦100
m≦10
0≦xi,yi≦100
方針
まずは、線分の端点および、線分同士の交点を全列挙する。
この点を頂点とするグラフを作る。
それぞれの線分について、
自分の上に乗っている点を見つけてきて、
隣接する点同士に、対応する容量を加算する。
全部の加算が終わったら、容量をもとにグラフを作って、
スタートからゴールへ最大流を流す。
EPSを変えまくったら通った。
spaghetti sourceのintersectSPは不正確(?)なので使うと通らないっぽい。
ccwを使って判定するとよい。
のだが、ccwにEPSがないのでそのままでは通らず、ccwにEPSを入れたら通った。
ソースコード
const double EPS=1e-4, INF=1e12; //最大流のコードは省略 void add_edge(Graph &g, int s,int t,int w){ g[s].pb(Edge(s,t,w)); g[t].pb(Edge(t,s,0)); } typedef complex<double> P; namespace std { bool operator < (const P& a, const P& b) { return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b); } } double cross(const P& a, const P& b) { return imag(conj(a)*b); } double dot(const P& a, const P& b) { return real(conj(a)*b); } struct L : public vector<P> { L(const P &a, const P &b) { push_back(a); push_back(b); } }; typedef vector<P> G; struct C { P p; double r; C(const P &p, double r) : p(p), r(r) { } }; int ccw(P a, P b, P c) { b -= a; c -= a; if (cross(b, c) > EPS) return +1; // counter clockwise if (cross(b, c) < -EPS) return -1; // clockwise if (dot(b, c) < EPS) return +2; // c--a--b on line if (norm(b) < norm(c)) return -2; // a--b--c on line return 0; } bool intersectLS(const L &l, const L &s) { return cross(l[1]-l[0], s[0]-l[0])* // s[0] is left of l cross(l[1]-l[0], s[1]-l[0]) < EPS; // s[1] is right of l } bool intersectSS(const L &s, const L &t) { return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0; } bool intersectSP(const L &s, const P &p) { rep(i,2)if(abs(s[i]-p)<EPS)return 1; return ccw(p,s[1],s[0])==2; } P crosspoint(const L &l, const L &m) { double A = cross(l[1] - l[0], m[1] - m[0]); double B = cross(l[1] - l[0], l[1] - m[0]); if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!! return m[0] + B / A * (m[1] - m[0]); } map<P,int> id; void push(vector<P> &ps,const P &p){ if(id.count(p))return; rep(i,ps.size())if(abs(ps[i]-p)<EPS){ id[p]=i; return; } id[p]=ps.size(); ps.pb(p); } struct cmp{ P o; cmp(P p):o(p){} bool operator()(const P&a,const P&b)const{ return abs(a-o)<abs(b-o); } }; int n,m,w[500]; int main(){ vector<L> ls; vector<P> ps; cin>>n; rep(i,n){ double ax,ay,bx,by; cin>>ax>>ay>>bx>>by>>w[i]; ls.pb(L(P(ax,ay),P(bx,by))); push(ps,P(ax,ay)); push(ps,P(bx,by)); } cin>>m; vector<P> ss; double x,y; rep(i,m){ cin>>x>>y; ss.pb(P(x,y)); push(ps,P(x,y)); } cin>>x>>y; P g(x,y); push(ps,g); rep(i,n)rep(j,i)if(intersectSS(ls[i],ls[j])){ P cp=crosspoint(ls[i],ls[j]); push(ps,cp); } int V=ps.size(); Graph graph(V+1); int s=V, t=id[g]; rep(i,m){ add_edge(graph,s,id[ss[i]],inf); } vector<vector<double> > width(V,vector<double>(V)); rep(i,n){ vector<P> online; rep(j,V)if(intersectSP(ls[i],ps[j]))online.pb(ps[j]); sort(all(online),cmp(ls[i][0])); const double dist=abs(ls[i][0]-ls[i][1]); rep(j,online.size()-1){ double tw=w[i]*abs(online[j]-online[j+1])/dist; width[id[online[j]]][id[online[j+1]]]+=tw; width[id[online[j+1]]][id[online[j]]]+=tw; } } rep(i,V)rep(j,V)if(width[i][j]>EPS)add_edge(graph,i,j,(int)(width[i][j]+EPS)); int ans=maximumFlow(graph,s,t); cout<<ans<<endl; return 0; }