您的位置:首页 > 理论基础 > 计算机网络

Bzoj1822:[JSOI2010]Frozen Nova 冷冻波:计算几何+网络流

2016-06-20 09:44 483 查看
题目链接:[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();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息