Bzoj1822:[JSOI2010]Frozen Nova 冷凍波:計算幾何+網絡流

題目鏈接:[JSOI2010]Frozen Nova 冷凍波

二分答案,把最優性問題轉換爲判定性問題

對於判斷樹木是否與線段相交,分兩種情況討論:

1:圓心作線段的垂線垂足不在線段上

2:圓心作線段的垂線垂足在線段上

對於1,直接比較圓心與線段兩個端點距離的最小值是否小於半徑

對於2,算出垂線長度後比較

區分1、2兩種情況用點積即可,相當於間接判斷cos的值得正負

#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=251;
const int inf=0x7fffffff/3;
struct Lich{double x,y,r;int t;}l[maxn];
struct point{double x,y;};
struct Spirit{double x,y;}spr[maxn];
struct Tree{double x,y,r;}t[maxn];
struct edge{int to,next,w;}G[maxn*maxn*2];
int tot=0,n,m,tr,h[10000],vis[10000],mx=0;
int S,T,cur[10000],mp[maxn][maxn],mark[maxn];

void add(int x,int y,int z){
	G[++tot].to=y;G[tot].next=h[x];h[x]=tot;G[tot].w=z;
	G[++tot].to=x;G[tot].next=h[y];h[y]=tot;G[tot].w=0;
}

double powe(double x){return x*x;}

double qdis(Lich a,Spirit b){
	return sqrt(powe(a.x-b.x)+powe(a.y-b.y));
}

double qdis2(double a,double b,double c,double d){
	return sqrt(powe(a-c)+powe(b-d));
}

double cross(point a,point b,point c){
	double x1=b.x-a.x,y1=b.y-a.y;
	double x2=c.x-a.x,y2=c.y-a.y;
	return x1*y2-x2*y1;
}

double dot(point a,point b,point c){
    double x1=b.x-a.x,y1=b.y-a.y;
	double x2=c.x-a.x,y2=c.y-a.y;
	return x1*x2+y1*y2;
}

bool in_cir(Lich a,Spirit b,Tree c){
	point tmp1,tmp2,tmp3;
	tmp1=(point){a.x,a.y};
	tmp2=(point){b.x,b.y};
	tmp3=(point){c.x,c.y};
	if (dot(tmp3,tmp1,tmp2)>=0) return min(qdis2(a.x,a.y,c.x,c.y),qdis2(b.x,b.y,c.x,c.y))<=c.r;
	else return abs(cross(tmp1,tmp3,tmp2))/qdis(a,b)<=c.r;
}

bool bfs(){
	for (int i=S;i<=T;++i) vis[i]=-1;
	queue<int>q; q.push(S); vis[S]=0;
	while (!q.empty()){
		int u=q.front(); q.pop();
		for (int i=h[u];i;i=G[i].next){
			int v=G[i].to;
			if (vis[v]==-1&&G[i].w)
			    vis[v]=vis[u]+1,q.push(v);
		}
	}return vis[T]!=-1;
}

int dfs(int x,int f){
	if (!f||x==T) return f;
	int w,used=0;
	for (int i=cur[x];i;i=G[i].next)
	    if (vis[G[i].to]==vis[x]+1){
			w=f-used;
			w=dfs(G[i].to,min(w,G[i].w));
			G[i].w-=w; G[i^1].w+=w;
			used+=w; if (G[i].w) cur[x]=i;
			if (used==f) return used;
	    }
	if (!used) vis[x]=-1;
	return used;
}

int dinic(){
	int ret=0;
	while(bfs()){
		for (int i=S;i<=T;++i) cur[i]=h[i];
		ret+=dfs(S,inf);
	}return ret;
}

bool check(int x){
	tot=1;
	for (int i=S;i<=T;++i) h[i]=0;
	for (int i=1;i<=n;++i){
		int tmp=x/l[i].t+1;
		add(S,i,tmp);
	}
	for (int i=1;i<=n;++i)
	    for (int j=1;j<=m;++j)
	        if (mp[i][j]) add(i,j+n,1);
	for (int i=1;i<=m;++i) add(i+n,T,1);
	int sum=dinic();
	return sum==m;
}

void solve(){
	int l=0,r=m*mx,ans=inf;
	while (l<=r){
		int mid=(l+r)>>1;
		if (check(mid)) r=mid-1,ans=min(ans,mid);
		else l=mid+1;
	}printf("%d\n",ans==inf?-1:ans);
}

int main(){
	scanf("%d%d%d",&n,&m,&tr);
	S=0; T=n+m+1;
	for (int i=1;i<=n;++i) scanf("%lf%lf%lf%d",&l[i].x,&l[i].y,&l[i].r,&l[i].t);
	for (int i=1;i<=n;++i) mx=max(mx,l[i].t);
	for (int i=1;i<=m;++i) scanf("%lf%lf",&spr[i].x,&spr[i].y);
	for (int i=1;i<=tr;++i) scanf("%lf%lf%lf",&t[i].x,&t[i].y,&t[i].r);
	for (int i=1;i<=n;++i)
	    for (int j=1;j<=m;++j){
			double dist=qdis(l[i],spr[j]);
			if (dist>l[i].r) continue;
			bool flag=1;
			for (int k=1;k<=tr;++k)
			    if(in_cir(l[i],spr[j],t[k])){flag=0;break;}
			if (flag) mp[i][j]=1,mark[j]=1;
	    }
	for (int i=1;i<=m;++i)
		if (!mark[i]){printf("-1");return 0;}
	solve();
}



發佈了112 篇原創文章 · 獲贊 12 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章