http://www.lydsy.com/JudgeOnline/problem.php?id=2965

http://www.tsinsen.com/A1385

平面图网络流。

首先我们要将平面图转化成对偶图。

将每条无向边拆成两个向量,从一条未访问过的向量开始,找到逆时针方向上第一个向量,然后继续访问,直到形成环,这样就找到了一条轮廓线,且内部在向量的右边。

如图从为访问过的边1->8开始,找到8->7,然后继续找到7->1,形成了环,这样找到了一条轮廓线。内部在1->8,8->7,7->1的右边。

我们称这种轮廓线为内轮廓线

(图1)

但是如果从1->2开始找,会找到下图这样的轮廓线,并且我们认为多边形在向量的右边。

我们称这种轮廓线为外轮廓线

(图2)

内轮廓线(图1)和外轮廓线(图2)的区别是:内轮廓线的点的顺序是顺时针,外轮廓线的点的顺序是逆时针。

这种情况我们可以用有向面积判断。

如果点的顺序是顺时针,那么有向面积为负,如图1;如果点的顺序是逆时针,那么有向面积为正,如图2。

这样我们就区分了内轮廓线和外轮廓线。

现在我们找出了全部轮廓线,接下来求域。

为了方便,我们在原图的基础上用一个足够大的矩形”框"住所有点。

我们称连通的空白部分为

我们称外部的无限区域为无限域。无限域是这样的(虚线为外轮廓线,灰色部分为无限域):

(图3)

无限域有且仅有一个,且只有一条外轮廓线,因为我们用了一个足够大的矩形”框"住所有点。

除无限域外,其他的域称为有限域。有限域是这样的(实线为内轮廓线,虚线为外轮廓线,灰色部分为有限域):

(图4)

有限域一定有一条内轮廓线,可能有若干条外轮廓线。

内轮廓线一定与有限域对应,外轮廓线可能与有限域或无限域对应。

我们怎么找外轮廓线对应的有限域或无限域呢?

如果没有内轮廓线严格包住外轮廓线,那么这条外轮廓线对应唯一的无限域,如图3。

如果有内轮廓线严格包住这条外轮廓线,我们就找严格包住这条外轮廓线的面积最小的内轮廓线,那么这条外轮廓线对应的有限域就是这条内轮廓线对应的有限域。

判断外轮廓线有没有被某条内轮廓线可以随便取外轮廓线上的一点,然后用射线法判断这个点是否严格在内轮廓线(即判断一个点是否在简单多边形内)。

现在已经把域求出来了。

我们还判断古迹属于哪个域。

直接找到严格包住这个古迹的面积最小的内轮廓线(即简单多边形),判断古迹是否被严格包含可以用射线法(即判断一个点是否在简单多边形内)。

接下来就是网络流的建图了。

每个域看成一个结点,无限域就是汇点T。

一条边两侧的两个域我们已经求出来的,直接在这两个域之间连一条容量为建篱笆代价的边。

由于只有10个古迹,我们直接2^10枚举哪些古迹一定要被围起来。

如果某个古迹一定要被围起来,就从源点S到这个古迹所在的域连边。

根据最大流最小割定理,直接跑网络流即可。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b) for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define p_b push_back
#define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int sgn(DB x){if(abs(x)<EPS)return ;return(x>)?:-;}
const DB Pi=acos(-1.0); inline int gint()
{
int res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
}
inline LL gll()
{
LL res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
} const int maxP=;
const int maxN=+;
const int maxM=maxN*(maxN-)/;
const int maxcnt=maxM+-maxN;
const LL INF=1LL<<; struct Tpoint
{
int x,y;
inline Tpoint(int _x=,int _y=){x=_x;y=_y;}
inline void input(){x=gint();y=gint();}
}; struct Tseg
{
Tpoint st,en;
DB alpha;
int id,u,v,flag;
LL cost;
Tseg *another;
inline Tseg(Tpoint _st=Tpoint(),Tpoint _en=Tpoint(),int _u=,int _v=,LL _cost=){st=_st;en=_en;u=_u;v=_v;cost=_cost;alpha=atan2(en.y-st.y,en.x-st.x);id=;flag=;another=;}
}; inline LL det(Tpoint p0,Tpoint p1,Tpoint p2){return LL(p1.x-p0.x)*LL(p2.y-p0.y)-LL(p2.x-p0.x)*LL(p1.y-p0.y);} int P,N,M;
Tpoint arch[maxP+],p[maxN+];
Tseg line[*maxM+];
int belong[maxP+];
LL ans[maxP+]; vector<Tseg*> e[maxN+];
inline bool cmp(Tseg *a,Tseg *b){return a->alpha<b->alpha;} inline void insertline(int i,int u,int v,LL cost)
{
line[i<<]=Tseg(p[u],p[v],u,v,cost);
line[i<<^]=Tseg(p[v],p[u],v,u,cost);
line[i<<].another=&line[i<<^];
line[i<<^].another=&line[i<<];
e[u].p_b(&line[i<<]);
e[v].p_b(&line[i<<^]);
line[i<<].id=i<<;
line[i<<^].id=i<<^;
} int cnt;
struct Thull
{
int n;
LL area;//如果点的顺序是顺时针,area为负数;如果点的顺序是逆时针,area为正数
Tpoint a[maxN+];
int eid[maxN+];
inline void insert(Tpoint x,int t){n++;a[n]=x;eid[n]=t;}
}h[maxcnt+];
int out[maxcnt+]; inline int inhull(Thull &plg,const Tpoint &a)
{
int i,count = ;
int d1,d2,d3;
plg.a[plg.n+]= plg.a[];
re(i,,plg.n)
{
if(plg.a[i].x==a.x && plg.a[i].y==a.y) return ;
d1=plg.a[i+].y-plg.a[i].y;
d2=a.y-plg.a[i].y;
d3=plg.a[i+].y-a.y;
if (d1> && d2> && d3>= && det(plg.a[i],plg.a[i+],a)>) count++;
if (d1< && d2<= && d3< && det(plg.a[i+],plg.a[i],a)>) count++;
}
return count&;
} inline void find(Tseg *l)
{
int i;
++cnt;
int start=l->u,now=l->v;
LL area=det(Tpoint(),l->st,l->en);
l->flag=cnt;
h[cnt].insert(p[now],l->id);
while(now!=start)
{
vector<Tseg*>::iterator it=upper_bound(e[now].begin(),e[now].end(),l->another,cmp);
if(it==e[now].end())it=e[now].begin();
l=*it;
area+=det(Tpoint(),l->st,l->en);
l->flag=cnt;
now=l->v;
h[cnt].insert(p[now],l->id);
}
h[cnt].area=area;
out[cnt]=(area>);
if(!out[cnt])
{
re(i,,P)
if(inhull(h[cnt],arch[i]))
if(!belong[i] || abs(h[cnt].area)<abs(h[belong[i]].area))
belong[i]=cnt;
}
} inline void check(int r)
{
int i,be=-;
re(i,,cnt)if(out[i]==)
if(inhull(h[i],h[r].a[]))
if(be==- || abs(h[i].area)<abs(h[be].area))
be=i;
if(be==-)return;
re(i,,h[r].n)line[h[r].eid[i]].flag=be;
out[r]=;
} int S,T,now,first[maxcnt+],last[maxcnt+];
struct Tedge{int v,next;LL flow;}edge[*(maxP+*maxM)+];
inline void insert(int u,int v,LL flow)
{
now++;edge[now].v=v;edge[now].flow=flow;edge[now].next=first[u];first[u]=now;
now++;edge[now].v=u;edge[now].flow=;edge[now].next=first[v];first[v]=now;
}
inline int flow_build(int state)
{
int i,res=;
S=;re(i,,cnt)if(out[i]==)T=i;
mmst(first,-);now=-;
#define wei(state,k) ((state>>(k-1))&1)
re(i,,P)if(wei(state,i))res++,insert(S,belong[i],INF);
for(i=;i<=(M<<^);i+=)
{
int u=line[i].flag,v=line[i^].flag;LL flow=line[i].cost;
insert(u,v,flow);
insert(v,u,flow);
}
return res;
} int head,tail,que[maxcnt+];
int level[maxcnt+];
inline int Dinic_Build()
{
int i;
re(i,,cnt)level[i]=;
level[que[head=tail=]=S]=;
while(head<=tail)
{
int u=que[head++],v;LL flow;
for(i=first[u],v=edge[i].v,flow=edge[i].flow;i!=-;i=edge[i].next,v=edge[i].v,flow=edge[i].flow)
if(flow> && !level[v])
level[que[++tail]=v]=level[u]+;
}
return level[T];
}
inline LL Dinic(int u,LL delta)
{
if(u==T)return delta;
LL res=;int &i=last[u],v;LL flow;
for(v=edge[i].v,flow=edge[i].flow;i!=-;i=edge[i].next,v=edge[i].v,flow=edge[i].flow)
if(flow> && level[u]+==level[v])
{
LL temp=Dinic(v,min(flow,delta));
delta-=temp;
res+=temp;
edge[i].flow-=temp;
edge[i^].flow+=temp;
if(delta==)return res;
}
return res;
} int main()
{
freopen("bzoj2965.in","r",stdin);
freopen("bzoj2965.out","w",stdout);
int i;
P=gint();N=gint();M=gint();
re(i,,P)arch[i].input();
int minx=<<,maxx=-<<,miny=<<,maxy=-<<;
re(i,,N){p[i].input();upmin(minx,p[i].x);upmax(maxx,p[i].x);upmin(miny,p[i].y);upmax(maxy,p[i].y);}
minx--;maxx++;miny--;maxy++;
p[++N]=Tpoint(maxx,maxy);
p[++N]=Tpoint(maxx,miny);
p[++N]=Tpoint(minx,miny);
p[++N]=Tpoint(minx,maxy);
re(i,,M){int u=gint(),v=gint();LL cost=gll();insertline(i,u,v,cost);}
insertline(++M,N-,N-,INF);
insertline(++M,N-,N-,INF);
insertline(++M,N-,N,INF);
insertline(++M,N,N-,INF);
re(i,,N)sort(e[i].begin(),e[i].end(),cmp);
re(i,,M<<^)if(!line[i].flag)find(&line[i]);
re(i,,cnt)if(out[i]==)check(i);
mmst(ans,0x3f);
for(int state=;state<<<P;state++)
{
int ge=flow_build(state);LL maxflow=;
while(Dinic_Build())
{
re(i,,cnt+)last[i]=first[i];
maxflow+=Dinic(S,INF);
}
upmin(ans[ge],maxflow);
}
re(i,,P)cout<<ans[i]<<endl;
return ;
}

我现在的心情就像一个去了皮的大土豆~OTATO

bzoj2965的更多相关文章

  1. BZOJ2965 : 保护古迹

    首先要将这个图连通,方法是通过扫描线+set求出每个连通块最高的点上方的第一条边,然后向交点连边. 然后把边拆成两条双向边,每次找到一条没走过的边,找到极角排序后它的反向边的后继,直到回到这条边. 根 ...

随机推荐

  1. Java LinkedList 源码分析

    简介 LinkedList 是一个常用的集合类,用于顺序存储元素. LinkedList 经常和 ArrayList 一起被提及.大部分人应该都知道 ArrayList 内部采用数组保存元素,适合用于 ...

  2. Oracle 表分析

    ANALYZE TABLE SeikyuTbl COMPUTE Statistics FOR TABLE FOR ALL COLUMNS FOR ALL INDEXES ; 一.优化器的优化方式 Or ...

  3. mysql中的unique

    distinct可以把重复的行去掉,查询时候用select distinct * from ...; unique在MySQL中是完整性约束里的一种,如果某列的值需要是唯一的那么就添加UNIQUE约束 ...

  4. Windows下oracle打补丁步骤

    1.Oracle官网下载对应的补丁文件(需要oracle支持账号才能下载) 2.设置ORACLE_HOME set oracle_home=F:\oracle\product\11.2.0\dbhom ...

  5. 【MySQL】关于MySQL错误日志信息的收集

    为方便维护MySQL,写了个脚本用以提供收集错误信息的接口.这些错误信息来自与MySQL错误日志,而 通过grep mysql可以获取error-log的路径. #!/usr/bin/env pyth ...

  6. RIP协议两个版本号对不连续子网的支持情况实验

    (增加时注明"会员咨询")

  7. java\C#\php主流语言实现FMS流媒体传输协议RTMP的开源组件

    java:bladeDS http://sourceforge.net/adobe/blazeds/wiki/Home/ .net:FlourinceFX http://www.fluorinefx. ...

  8. vb的LINQ实现

    vb实现LINQ非常简单的例子: Dim numbers() As Integer = {1, 2, 3, 4, 5, 6, 7} Dim allNumbers = From number In nu ...

  9. MySql用statement实现DDL,DML,DQL的操作Demo

    Demo1 Connection connection=null; Statement stmt=null; int result=-1; try { Class.forName("com. ...

  10. HibernateTemplate常用方法总结

    HibernateTemplate常用方法 (本文章内容相当于转载自:http://www.tuicool.com/articles/fU7FV3,只是整理了一下内容结构和修改了部分内容,方便阅读) ...