zoukankan      html  css  js  c++  java
  • BZOJ2965: 保护古迹

    2965: 保护古迹

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 382  Solved: 163
    [Submit][Status][Discuss]

    Description

      某校由于历史悠久,校园中有大量的名胜古迹。为了更好地保护这些古迹,学校决定用篱笆将这些古迹围起来。
      现在已知有p个地点的古迹需要保护。这些古迹可以看做二维平面上的整数点。有n个点可以作为篱笆的端点,这些端点的坐标也为二维平面上的整数。端点用1到n的整数编号。
      有m对端点之间可以修建篱笆。用(u,v,w)描述一段可以修建的篱笆,表示端点u和端点v之间可以花费w的代价修建一段。篱笆都看做直线段。为了方便设计,这些可以修建的篱笆都是不会相交的(只会在端点处相交)。
      将一个古迹围起来是指存在一个由篱笆构成的简单多边形,这个古迹在该多边形内部。
      由于经费问题,学校希望修建篱笆的花费最小。你需要输出将至少1个,2个,…,p个古迹围起来的最小花费。

    Input

      第一行包含三个正整数p,n,m表示古迹的个数,端点个数和可以修建的篱笆条数。
      接下来p行,每行包含两个整数,表示每个古迹的坐标。
      接下来n行,每行包含两个整数,表示每个端点的坐标。这些端点按照输入的顺序依次用1到n的整数编号。
      最后m行,每行包含三个非负整数u,v,w,表示可以在端点u和端点v之间花w的代价修建一段篱笆。

    Output

      输出p行,分别表示将至少1个,2个,…,p个古迹围起来的最小花费。

    Sample Input

    3 9 15
    -2 2
    2 1
    2 -1
    3 0
    3 2
    1 2
    -1 3
    -3 3
    -2 1
    1 0
    2 -2
    2 -3
    1 2 20
    1 7 40
    1 8 10
    1 9 100
    2 3 50
    3 4 1000
    3 7 10
    4 5 10
    4 6 10
    4 7 1000
    5 6 10
    6 7 1000
    7 8 120
    7 9 10
    8 9 10

    Sample Output

    30
    100
    140

    HINT


     对于100%的数据,n≤100, m≤C(n,2),p≤10。所有坐标位置的两维绝对值不超过109,u,v不超过n,w不超过106

      保证可以修建的篱笆不会经过古迹。保证可以修建的两段篱笆不会在非端点处相交或重合。保证至少存在一种方案可以包围所有古迹。保证n个点互不相同。

     

    思路{

      同样是平面图转对偶图后(基本平面图的划分算法顺便求出点所属的区域)p较小,

      可以直接枚举要保护的古迹,直接跑最小割都可以了用Inf排除不参与决策的边.

    }

    #include<bits/stdc++.h>
    #define RG register
    #define il inline 
    #define N 10010
    #define inf (1<<30)
    #define LL long long
    #define db double
    using namespace std;
    struct ed{int nxt,to,c;}e[N*2];
    int head[N],tot,dep[N];
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void link(int u,int v,int c){e[tot].nxt=head[u];e[tot].to=v;e[tot].c=c;head[u]=tot++;}
    void LINK(int u,int v,int c){link(u,v,c),link(v,u,c);}
    bool BFS(int s,int t){
      queue<int>que;
      while(!que.empty())que.pop();
      memset(dep,0,sizeof(dep));
      dep[s]=1;que.push(s);
      while(!que.empty()){
        int u=que.front();que.pop();
        for(int i=head[u];i!=-1;i=e[i].nxt){
          int v=e[i].to;if(!dep[v]&&e[i].c){
        dep[v]=dep[u]+1;
        if(v==t)return true;
        que.push(v);
          }
        }
      }return false;
    }
    int dinic(int s,int t,int T){
      if(s==t)return T;int tag(0);
      for(int i=head[s];i!=-1;i=e[i].nxt)if(dep[e[i].to]==dep[s]+1&&e[i].c){
          int v=e[i].to;
          int d=dinic(v,t,min(T-tag,e[i].c));
          e[i].c-=d,e[i^1].c+=d;tag+=d;
          if(tag==T)break;
        }if(!tag)dep[s]=0;return tag;
    }
    int maxflow(int s,int t){
      int flow(0);
      while(BFS(s,t))flow+=dinic(s,t,inf);
      return flow;
    }
     
    struct point{
      db x,y;
      point() {}
      point(db X,db Y):x(X),y(Y) {}
      point operator +(const point & a)const{return point(x+a.x,y+a.y);}
      point operator -(const point & a)const{return point(x-a.x,y-a.y);}
      point operator *(const db & k)const{return point(x*k,y*k);}
      db operator *(const point & a)const{return x*a.y-y*a.x;}
      db len(){return x*x+y*y;}
      void read(){scanf("%lf%lf",&x,&y);}
    }p[N],a[N];
    struct Line{
      point st,v;
      int fir,to;
      int flag,val;
      db k;
      Line * re;
      Line() {}
      Line(point a,point b,int F,int T,int d):st(a),v(b),fir(F),to(T),val(d) {
        flag=0;
        k=atan2(v.y,v.x);
      }
    }l[N];
     
    bool Comp(Line *l1,Line *l2){return l1->k<l2->k;}
    vector<Line *>ex[N];
    int sum,n,m,idn,BL[N];bool vis[N];
    bool check(Line *l1,point p){
      return (l1->v*(p-l1->st))>0;
    }
    bool BZ[N];
    void find(Line *l1){
      memset(vis,true,sizeof(vis));
      for(int i=1;i<=sum;++i)if(vis[i])vis[i]=!check(l1,a[i]);
      int sta=l1->fir,now=l1->to;
      db s=p[l1->fir]*p[l1->to];l1->flag=idn;
      do{
        vector<Line * >::iterator it=upper_bound(ex[now].begin(),ex[now].end(),l1->re,Comp);
        if(it==ex[now].end())
          it=ex[now].begin();
        l1=*it;
        now=l1->to;l1->flag=idn;
        l1->flag=idn;s+=p[l1->fir]*p[l1->to];
        for(int i=1;i<=sum;++i)if(vis[i])vis[i]=!check(l1,a[i]);
      }while(now!=sta);
      for(int i=1;i<=sum;++i)if(vis[i])BL[i]=idn;
      if(s>0)BZ[idn]=true;
    }
    int T=1100;int ans[N];
    struct edge{
      int fir,to,len;
      edge() {}
      edge(int F,int To,int W):fir(F),to(To),len(W) {
        if(BZ[F])fir=T;
        if(BZ[To])to=T;
      }
    }E[N];int sig;
    int build(int x){
      int num(0);clear();
      for(int i=1;i<=sum;++i){
        if((x>>(i-1))&1){
          LINK(0,BL[i],inf);
          num++;
        }
      }
      for(int i=1;i<=sig;++i)LINK(E[i].fir,E[i].to,E[i].len);
      return num;
    }
    int main(){
      scanf("%d%d%d",&sum,&n,&m);
      for(int i=1;i<=sum;++i)a[i].read();
      for(int i=1;i<=n;++i)p[i].read();
      for(int i=1;i<=m;++i){
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        l[(i<<1)-1]=Line(p[x],p[y]-p[x],x,y,w);
        l[(i<<1)]=Line(p[y],p[x]-p[y],y,x,w);
        l[(i<<1)-1].re=&l[(i<<1)];
        l[(i<<1)].re=&l[(i<<1)-1];
        ex[x].push_back(&l[(i<<1)-1]);
        ex[y].push_back(&l[(i<<1)]);
      }
      for(int i=1;i<=n;++i)sort(ex[i].begin(),ex[i].end(),Comp);
      for(int i=1;i<=2*m;++i)if(!l[i].flag)idn++,find(&l[i]);
      for(int i=1;i<=2*m;i+=2)
        E[++sig]=edge(l[i].flag,l[i+1].flag,l[i].val);
      memset(ans,127/3,sizeof(ans));
      for(int i=1;i<(1<<sum);++i){
        int cnt=build(i);
        ans[cnt]=min(ans[cnt],maxflow(0,T));
      }
      for(int i=1;i<=sum;++i)
        cout<<ans[i]<<"
    ";
      return 0;
    }
    
  • 相关阅读:
    多播委托和匿名方法再加上Lambda表达式
    委托
    从警察抓小偷看委托
    StringBuilder
    C#修饰符详解
    数据结构与算法之队列
    数据结构与算法之栈
    win10重复安装
    网络编程基础
    PrintPreviewControl
  • 原文地址:https://www.cnblogs.com/zzmmm/p/7476490.html
Copyright © 2011-2022 走看看