BZOJ2965 : 保护古迹

首先要将这个图连通,方法是通过扫描线+set求出每个连通块最高的点上方的第一条边,然后向交点连边。

然后把边拆成两条双向边,每次找到一条没走过的边,找到极角排序后它的反向边的后继,直到回到这条边。

根据叉积可以求出面积,如果面积非负,那么就说明找到了一个封闭区域。

然后再进行一次扫描线,找到一个点上方最低的边,即可完成点定位。

时间复杂度$O(m\log m)$。

求出对偶图之后,暴力枚举所有必须保护的古迹,建图求最小割即可。

#include<cstdio>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
const double eps=1e-8,inf=1000000010;
const int N=510,M=50010,INF=~0U>>2;
int n,m,q,cnt,i,x,y,z;
inline int sgn(double x){
  if(fabs(x)<eps)return 0;
  return x>0?1:-1;
}
struct P{
  double x,y;
  P(){}
  P(double _x,double _y){x=_x,y=_y;}
  double operator*(const P&b){return x*b.y-y*b.x;}
}a[N],b[N];
struct E{
  int x,y,z;double o;
  E(){}
  E(int _x,int _y,int _z=-1){x=_x,y=_y,z=_z,o=atan2(a[y].x-a[x].x,a[y].y-a[x].y);}
}e[M];
bool del[M],ex[M];int from[M],id[N];
struct EV{
  double x;int y,t;
  EV(){}
  EV(double _x,int _y,int _t){x=_x,y=_y,t=_t;}
}ev[M<<1];
inline bool cmpEV(const EV&a,const EV&b){
  if(sgn(a.x-b.x))return a.x<b.x;
  return a.t<b.t;
}
namespace GetArea{
struct cmp{bool operator()(int a,int b){return e[a].o<e[b].o;}};
set<int,cmp>g[N];set<int,cmp>::iterator k;int i,j,q[M],t;
void work(){
  for(i=0;i<m+m;i++)if(!del[i]&&!ex[i]){
    for(q[t=1]=j=i;;q[++t]=j=*k){
      k=g[e[j].y].find(j^1);k++;
      if(k==g[e[j].y].end())k=g[e[j].y].begin();
      if(*k==i)break;
    }
    double s=0;
    for(j=1;j<=t;j++)s+=a[e[q[j]].x]*a[e[q[j]].y],del[q[j]]=1;
    if(sgn(s)<0)continue;
    for(cnt++,j=1;j<=t;j++)from[q[j]]=cnt;
  }
}
}
namespace ScanLine{
struct cmp{
  bool operator()(int A,int B){
    if(e[A].x==e[B].x)return e[A].o>e[B].o;
    double x=min(a[e[A].x].x,a[e[B].x].x),
           yA=(a[e[A].x].y-a[e[A].y].y)*(x-a[e[A].y].x)/(a[e[A].x].x-a[e[A].y].x)+a[e[A].y].y,
           yB=(a[e[B].x].y-a[e[B].y].y)*(x-a[e[B].y].x)/(a[e[B].x].x-a[e[B].y].x)+a[e[B].y].y;
    return yA>yB;
  }
};
set<int,cmp>T;
int cnt,i,j,k,g[M],v[M],nxt[M],ed,vis[N],t,tmp[N];
inline bool cmpC(int x,int y){return a[x].x<a[y].x;}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
  vis[x]=1;
  if(a[x].y>a[t].y)t=x;
  for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])dfs(v[i]);
}
inline double cal(int A,double x){
  return(a[e[A].x].y-a[e[A].y].y)*(x-a[e[A].y].x)/(a[e[A].x].x-a[e[A].y].x)+a[e[A].y].y;
}
void connect(){
  for(i=0;i<m+m;i++)add(e[i].x,e[i].y);
  for(i=1;i<=n;i++)if(!vis[i])dfs(t=i),ev[cnt++]=EV(a[t].x,t,2);
  for(i=0;i<m+m;i++)if(sgn(a[e[i].x].x-a[e[i].y].x)>0){
    ev[cnt++]=EV(a[e[i].y].x,i,1);
    ev[cnt++]=EV(a[e[i].x].x,i,0);
  }
  sort(ev,ev+cnt,cmpEV);
  a[n+1]=P(inf,inf);
  a[n+2]=P(-inf,inf);
  e[m+m]=E(n+1,n+2);
  T.insert(m+m);
  e[m+m+1]=E(n+2,n+1);
  n+=2,m++;
  for(ed=0,i=1;i<=n;i++)g[i]=0;
  for(i=0;i<cnt;i++){
    if(ev[i].t==0)T.erase(ev[i].y);
    if(ev[i].t==1)T.insert(ev[i].y);
    if(ev[i].t==2){
      a[n+1]=P(ev[i].x,a[ev[i].y].y+eps);
      a[n+2]=P(ev[i].x-1,a[ev[i].y].y+eps);
      e[m+m]=E(n+1,n+2);
      T.insert(m+m);
      set<int,cmp>::iterator j=T.find(m+m);
      j--,add(*j,ev[i].y);
      T.erase(m+m);
    }
  }
  int newm=m+m;
  for(i=0;i<m+m;i++){
    for(cnt=0,j=g[i];j;j=nxt[j]){
      if(!sgn(a[v[j]].x-a[e[i].x].x)){
        e[newm++]=E(v[j],e[i].x);
        e[newm++]=E(e[i].x,v[j]);
        continue;
      }
      if(!sgn(a[v[j]].x-a[e[i].y].x)){
        e[newm++]=E(v[j],e[i].y);
        e[newm++]=E(e[i].y,v[j]);
        continue;
      }
      tmp[++cnt]=v[j];
    }
    if(!cnt)continue;
    ex[i]=ex[i^1]=1;
    sort(tmp+1,tmp+cnt+1,cmpC);
    for(k=e[i].y,j=1;j<=cnt;k=n,j++){
      a[++n]=P(a[tmp[j]].x,cal(i,a[tmp[j]].x));
      e[newm++]=E(k,n,e[i].z);
      e[newm++]=E(n,k,e[i].z);
      e[newm++]=E(tmp[j],n,e[i].z);
      e[newm++]=E(n,tmp[j],e[i].z);
    }
    e[newm++]=E(n,e[i].x,e[i].z);
    e[newm++]=E(e[i].x,n,e[i].z);
  }
  m=newm/2;
}
void location(){
  for(i=cnt=0;i<m+m;i++)if(!ex[i]&&sgn(a[e[i].x].x-a[e[i].y].x)>0){
    ev[cnt++]=EV(a[e[i].y].x,i,1);
    ev[cnt++]=EV(a[e[i].x].x,i,0);
  }
  for(i=0;i<q;i++)ev[cnt++]=EV(b[i].x,i,2);
  sort(ev,ev+cnt,cmpEV);
  T.clear();
  for(i=0;i<cnt;i++){
    if(ev[i].t==0)T.erase(ev[i].y);
    if(ev[i].t==1)T.insert(ev[i].y);
    if(ev[i].t==2){
      a[n+1]=P(ev[i].x,b[ev[i].y].y);
      a[n+2]=P(ev[i].x-1,b[ev[i].y].y);
      e[m+m]=E(n+1,n+2);
      T.insert(m+m);
      set<int,cmp>::iterator j=T.find(m+m);
      if(j!=T.begin())j--,id[ev[i].y]=from[*j];
      T.erase(m+m);
    }
  }
}
}
namespace MinCut{
struct E{int t,f;E*nxt,*pair;}*g[N],*d[N],pool[M],*cur;
int mask,m,val[M],st[M],en[M],S,T,h[N],gap[N],maxflow,ans[N];
inline void add(int s,int t,int f){
  E*p=cur++;p->t=t;p->f=f;p->nxt=g[s];g[s]=p;
  p=cur++;p->t=s;p->f=0;p->nxt=g[t];g[t]=p;
  g[s]->pair=g[t];g[t]->pair=g[s];
}
int sap(int v,int flow){
  if(v==T)return flow;
  int rec=0;
  for(E*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){
    int ret=sap(p->t,min(flow-rec,p->f));
    p->f-=ret;p->pair->f+=ret;d[v]=p;
    if((rec+=ret)==flow)return flow;
  }
  if(!(--gap[h[v]]))h[S]=T;
  gap[++h[v]]++;d[v]=g[v];
  return rec;
}
void work(){
  for(i=1;i<=q;i++)ans[i]=INF;
  S=cnt+1;T=S+1;
  for(i=0;i<m;i++){
    if(!st[i])st[i]=T;
    if(!en[i])en[i]=T;
  }
  for(mask=1;mask<1<<q;mask++){
    for(cur=pool,i=0;i<=T;i++)g[i]=d[i]=NULL,h[i]=gap[i]=0;
    for(i=0;i<m;i++)add(st[i],en[i],val[i]),add(en[i],st[i],val[i]);
    for(i=0;i<q;i++)if(mask>>i&1)add(S,id[i],INF);
    for(gap[maxflow=0]=T,i=1;i<=T;i++)d[i]=g[i];
    while(h[S]<T)maxflow+=sap(S,INF);
    ans[__builtin_popcount(mask)]=min(ans[__builtin_popcount(mask)],maxflow);
  }
  for(i=1;i<=q;i++)printf("%d\n",ans[i]);
}
}
int main(){
  scanf("%d%d%d",&q,&n,&m);
  MinCut::m=m;
  for(i=0;i<q;i++)scanf("%lf%lf",&b[i].x,&b[i].y);
  for(i=1;i<=n;i++)scanf("%lf%lf",&a[i].x,&a[i].y);
  for(i=0;i<m;i++){
    scanf("%d%d%d",&x,&y,&MinCut::val[i]);
    e[i<<1]=E(x,y,i);
    e[i<<1|1]=E(y,x,i);
  }
  ScanLine::connect();
  for(i=0;i<m+m;i++)if(!ex[i])GetArea::g[e[i].x].insert(i);
  GetArea::work();
  ScanLine::location();
  for(i=0;i<m+m;i++)if(!ex[i]&&~e[i].z){
    MinCut::st[e[i].z]=from[i];
    MinCut::en[e[i].z]=from[i^1];
  }
  MinCut::work();
  return 0;
}

  

时间: 2024-08-26 15:57:53

BZOJ2965 : 保护古迹的相关文章

【BZOJ2965】保护古迹 平面图转对偶图,暴力,网络流

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43199045"); } 题意:自己看去吧. 题解:如果不考虑这道题的某些小数据范围, 那么正解应该是: 首先平面图转对偶图, 然后扫描线处理名胜古迹 过程中运用到邪恶的平衡树(就算是set也依然恶心) 或者用神奇方法Ⅰ判断(cheat)一个名胜古迹在

BZOJ 2965 保护古迹 平面图转对偶图+最小割

题目大意:给出一个平面图,这个平面图中分布着一些点,可以用平面图中的边将一些点围住,问围住k个点的最小花费是多少. 思路:这题重点是平面图转对偶图.做法不难理解.先将所有的边拆成两条,枚举所有的边,若这个边没有被标记过,那么就对这条边进行搜索,弄出来以这个边为一边的平面区域,可以顺时针或者逆时针.将所有边挂在这条边的起点上,在所有点上按照每条边的极角排序,每次找的时候找大于(或小于)当前边的反向边的第一条边作为搜索的下一条边.直到回到最开始的点.找边的过程中记录面积,判断面积的正负来判断这个平面

省选模拟24

我是谁? 鸽子王. \(T1:\) 不会 \(T2:\) 不会 \(T3:\) 首先联想到这道题:bzoj2965保护古迹 想到能不能转成对偶图跑最小割 然后发现并不能做... 但根据这个想到:对偶图的最小割\(<=>\)平面图的最短路 (以下坐标均指代交点) 继续推理容易发现只有一个关键点的时候,显然不会跨过(1,1)到关键点左上角的最短路 而当有多个关键点时一定不会跨过这些(1,1)到这些关键点的左上角的最短路树. 证明: 如图,因为画的路径是一个环,考虑环和树的相交关系 由于树的根位于环

【BZOJ2007】【Noi2010】海拔 平面图最小割转最短路

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43280891"); } 题解:这个模型很水,不需要极角序神马转对偶图,直接乱搞就行. 然后目的是把图割开,那么只需要跑S->T最短路就行. 要做平面图转对偶图不妨去这篇. [BZOJ2965]保护古迹 平面图转对偶图,暴力,网络流 还有就是某人

[NetworkFlow]网络流建模相关

流 网络流问题本质上是线性规划问题的应用之一,线性规划问题的标准形式是给出一组等式约束和不等式约束,要求最优化一个线性函数. 在流问题中,变量以流量的形式出现在问题中,我们给出一个流网络(以有向图的形式)来解决有关流的问题. 流是整个网络流问题的核心所在,它实际上是定义在流网络上的一个线性函数,在流网络中,每条边都有一个流量f(u,v),流f=∑v∈Vf(S,v) 流量f(u,v)是流问题中的变量,它有两个约束,一个是不等式,一个是等式 (1)容量限制:f(u,v)≤c(u,v) (2)流量平衡

bzoj2965

http://www.lydsy.com/JudgeOnline/problem.php?id=2965 http://www.tsinsen.com/A1385 平面图网络流. 首先我们要将平面图转化成对偶图. 将每条无向边拆成两个向量,从一条未访问过的向量开始,找到逆时针方向上第一个向量,然后继续访问,直到形成环,这样就找到了一条轮廓线,且内部在向量的右边. 如图从为访问过的边1->8开始,找到8->7,然后继续找到7->1,形成了环,这样找到了一条轮廓线.内部在1->8,8-

人工智能PK透明加密,数据安全保护谁能技高一筹

人工智能一直是全球的一大热点话题,从很久之前谷歌研发的人工智能机器人击败柯洁.李世石等众多围棋高手,到最近特斯拉CEO埃隆o马斯克投资的人工智能研究机构OpenAI研发的机器人击败了国外顶尖Dota 2玩家之一的Danil Ishutin.而重磅消息却是美国电商巨头亚马逊,已准备将人工智能技术用于商业服务中,计划将其用于云存储方面,用于保护用户数据的安全. 亚马逊的这一计划,主要是通过机器学习技术,自动识别.分类和保护用户保存在亚马逊云计算平台上的敏感数据.但引入人工智能技术之后,亚马逊的云存储

如何有效的对PDF文件进行加密保护

PDF是办公中保存资料数据文件不可或缺的一类电子文件工具软件,它的优势在于清晰的位图显示形式和良好的阅读体验,所以很多合同报告.电子书.技术文档.设计图纸等都越来越倾向这种存储方式.和普通的电子文档一样,如Word.Excel,PDF文件也存在信息安全泄漏风险,因此加密保护也是必不可少的.下面就来分享下如何对PDF进行权限设置和PDF文件加密操作. PDF格式的官方编辑器Adobe acrobat 软件为我们提供的口令加密包含"打开文档的口令"和"限制文档编辑打印口令&quo

在win10 LTSB版本中使用UWF组件,实现影子保护功能,提供稳定,高速的开发环境

Win10 LTSB,比win8好用,又没有APP功能,老机运行非常稳定.流畅.安装运行一段时间后,安装了UWF组件,提高安全性和流畅性. Windows UWF(统一写保护)组件,功能: 1.当内存盘用,加强性能,提高速度: 2.省SSD写入: 3.当还原卡用,防熊孩子 开启方法: 1.程序和功能→启用或关闭Windows功能,勾选"统一写入筛选器" 2.UWF设置 手动启动及设定 (要重新启动系统才生效,关机再开是没用的) : 用管理员模式打开控制台,挑选下列可使用命令行 uwfm