http://www.lydsy.com/JudgeOnline/problem.php?id=2965
平面图网络流。
首先我们要将平面图转化成对偶图。
将每条无向边拆成两个向量,从一条未访问过的向量开始,找到逆时针方向上第一个向量,然后继续访问,直到形成环,这样就找到了一条轮廓线,且内部在向量的右边。
如图从为访问过的边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-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxP=10; const int maxN=100+4; const int maxM=maxN*(maxN-1)/2; const int maxcnt=maxM+2-maxN; const LL INF=1LL<<50; struct Tpoint { int x,y; inline Tpoint(int _x=0,int _y=0){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=0,int _v=0,LL _cost=0){st=_st;en=_en;u=_u;v=_v;cost=_cost;alpha=atan2(en.y-st.y,en.x-st.x);id=0;flag=0;another=0;} }; 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+10],p[maxN+10]; Tseg line[2*maxM+100]; int belong[maxP+10]; LL ans[maxP+10]; vector<Tseg*> e[maxN+10]; 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<<1]=Tseg(p[u],p[v],u,v,cost); line[i<<1^1]=Tseg(p[v],p[u],v,u,cost); line[i<<1].another=&line[i<<1^1]; line[i<<1^1].another=&line[i<<1]; e[u].p_b(&line[i<<1]); e[v].p_b(&line[i<<1^1]); line[i<<1].id=i<<1; line[i<<1^1].id=i<<1^1; } int cnt; struct Thull { int n; LL area;//如果点的顺序是顺时针,area为负数;如果点的顺序是逆时针,area为正数 Tpoint a[maxN+100]; int eid[maxN+100]; inline void insert(Tpoint x,int t){n++;a[n]=x;eid[n]=t;} }h[maxcnt+100]; int out[maxcnt+100]; inline int inhull(Thull &plg,const Tpoint &a) { int i,count = 0; int d1,d2,d3; plg.a[plg.n+1]= plg.a[1]; re(i,1,plg.n) { if(plg.a[i].x==a.x && plg.a[i].y==a.y) return 0; d1=plg.a[i+1].y-plg.a[i].y; d2=a.y-plg.a[i].y; d3=plg.a[i+1].y-a.y; if (d1>0 && d2>0 && d3>=0 && det(plg.a[i],plg.a[i+1],a)>0) count++; if (d1<0 && d2<=0 && d3<0 && det(plg.a[i+1],plg.a[i],a)>0) count++; } return count&1; } 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>0); if(!out[cnt]) { re(i,1,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=-1; re(i,1,cnt)if(out[i]==0) if(inhull(h[i],h[r].a[1])) if(be==-1 || abs(h[i].area)<abs(h[be].area)) be=i; if(be==-1)return; re(i,1,h[r].n)line[h[r].eid[i]].flag=be; out[r]=2; } int S,T,now,first[maxcnt+100],last[maxcnt+100]; struct Tedge{int v,next;LL flow;}edge[2*(maxP+2*maxM)+1000000]; 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=0;edge[now].next=first[v];first[v]=now; } inline int flow_build(int state) { int i,res=0; S=0;re(i,1,cnt)if(out[i]==1)T=i; mmst(first,-1);now=-1; #define wei(state,k) ((state>>(k-1))&1) re(i,1,P)if(wei(state,i))res++,insert(S,belong[i],INF); for(i=2;i<=(M<<1^1);i+=2) { int u=line[i].flag,v=line[i^1].flag;LL flow=line[i].cost; insert(u,v,flow); insert(v,u,flow); } return res; } int head,tail,que[maxcnt+100]; int level[maxcnt+100]; inline int Dinic_Build() { int i; re(i,0,cnt)level[i]=0; level[que[head=tail=0]=S]=1; while(head<=tail) { int u=que[head++],v;LL flow; for(i=first[u],v=edge[i].v,flow=edge[i].flow;i!=-1;i=edge[i].next,v=edge[i].v,flow=edge[i].flow) if(flow>0 && !level[v]) level[que[++tail]=v]=level[u]+1; } return level[T]; } inline LL Dinic(int u,LL delta) { if(u==T)return delta; LL res=0;int &i=last[u],v;LL flow; for(v=edge[i].v,flow=edge[i].flow;i!=-1;i=edge[i].next,v=edge[i].v,flow=edge[i].flow) if(flow>0 && level[u]+1==level[v]) { LL temp=Dinic(v,min(flow,delta)); delta-=temp; res+=temp; edge[i].flow-=temp; edge[i^1].flow+=temp; if(delta==0)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,1,P)arch[i].input(); int minx=1<<30,maxx=-1<<30,miny=1<<30,maxy=-1<<30; re(i,1,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,1,M){int u=gint(),v=gint();LL cost=gll();insertline(i,u,v,cost);} insertline(++M,N-3,N-2,INF); insertline(++M,N-2,N-1,INF); insertline(++M,N-1,N,INF); insertline(++M,N,N-3,INF); re(i,1,N)sort(e[i].begin(),e[i].end(),cmp); re(i,2,M<<1^1)if(!line[i].flag)find(&line[i]); re(i,1,cnt)if(out[i]==1)check(i); mmst(ans,0x3f); for(int state=1;state<1<<P;state++) { int ge=flow_build(state);LL maxflow=0; while(Dinic_Build()) { re(i,0,cnt+1)last[i]=first[i]; maxflow+=Dinic(S,INF); } upmin(ans[ge],maxflow); } re(i,1,P)cout<<ans[i]<<endl; return 0; }
我现在的心情就像一个去了皮的大土豆~OTATO