bzoj2965

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-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;
  }
View Code

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

posted @ 2015-08-06 19:56  maijing  阅读(238)  评论(0编辑  收藏  举报