SGU 303 Great Berland Wall(计算几何判环+最小割)

题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=303

题意:给出平面上一些线段,已知这些线段只在端点处相交,且这些线段围成了若干封闭图形。每条线段有一个代价。有两个点分别位于两个封闭图形中。选择一些线段将两个点分开且这些线段的代价和最小?

思路:首先,找出所有的环。对于一条线段,每次找它的最左侧的作为下一条。将所有的环编号。然后找出给出的两个点在哪个环里。我用的环绕法判断是不是2PI。以给出的两个点所在环为源点 和汇点,有公共边的两个环连边费用为边的代价。接着跑s到t的最小割也就是最大流。从sDFS一次找到能遍历到的点。最后对于一条边,若其连接的两个点一个是被遍历到一个是未被遍历到则这条边所对应的原来的一条线段就是答案中的一个。







class point

{

public:

    i64 x,y;



    point(){}

    point(i64 _x,i64 _y)

    {

        x=_x;

        y=_y;

    }



    void get()

    {

        RD(x,y);

    }



    i64 operator*(point a)

    {

        return x*a.y-y*a.x;

    }



    point operator-(point a)

    {

        return point(x-a.x,y-a.y);

    }



    i64 operator^(point a)

    {

        return x*a.x+y*a.y;

    }



    double getAng(point a)

    {

        return atan2(1.0*(*this*a),((*this)^a)*1.0);

    }



    void print()

    {

        printf("(%lld,%lld)",x,y);

    }

};



class node

{

public:

    int u,v,w,next;

};



const int N=605;

map<i64,int> Map;

point a[N],S,T;

int n,m,head[N],e,s,t;

node edges[N];



int getId(point p)

{

    i64 t=(i64)(p.x+10000)*10000+(p.y+10000);

    if(Map.find(t)!=Map.end()) return Map[t];

    return Map[t]=++m;

}



void Add(int u,int v,int w)

{

    edges[e].u=u;

    edges[e].v=v;

    edges[e].w=w;

    edges[e].next=head[u];

    head[u]=e++;

}



int b[N];

i64 area;

vector<int> V[N];



i64 cross(int x,int y,int p)

{

    return (a[y]-a[x])*(a[p]-a[x]);

}



i64 cross(point x,point y,point p)

{

    return (y-x)*(p-x);

}











void DFS(int x,int id)

{

    b[id]=n;

    V[n].pb(id);

    int u=edges[id].u,v=edges[id].v,v1,i,p,k=-1;

    i64 X,Y,Z;

    if(u!=x) swap(u,v);

    for(i=head[v];i!=-1;i=edges[i].next)

    {

        v1=edges[i].v;

        if(v1==u) continue;

        if(k==-1)

        {

            k=i;

            p=v1;

            continue;

        }

        X=cross(a[u],a[v],a[v1]);

        Y=cross(a[u],a[v],a[p]);

        Z=cross(a[v],a[p],a[v1]);

        if(X>0&&Y<=0||X==0&&Y<0||X*Y>=0&&Z>=0) k=i,p=v1;

    }

    area+=a[u]*a[v];

    if(k!=-1&&!b[k]) DFS(v,k);

}



int isInside(point s,vector<int> V)

{

    int i;

    point u,v;

    double sum=0;

    FOR0(i,SZ(V))

    {

        u=a[edges[V[i]].u];

        v=a[edges[V[i]].v];

        sum+=(u-s).getAng(v-s);

    }

    return fabs(fabs(sum)-2*PI)<1e-5;

}



struct Node

{

    int u,v,cap,flow,next,visited,id;



    Node(){}

    Node(int _u,int _v,int _cap,int _next,int _id)

    {

        u=_u;

        v=_v;

        cap=_cap;

        next=_next;

        visited=0;

        id=_id;

    }

};





const int INF=1000000000;

const int M=100005;

int num[M],h[M],curedge[M],pre[M];

int queue[M];

Node edges1[1200005];

int head1[M],e1;





void add(int u,int v,int cap,int id)

{

    edges1[e1]=Node(u,v,cap,head1[u],id);

    head1[u]=e1++;

    edges1[e1]=Node(v,u,0,head1[v],id);

    head1[v]=e1++;

}







void BFS(int s,int t)

{

    memset(num,0,sizeof(num));

    memset(h,-1,sizeof(h));

    num[0]=1;

    int front=0,rear=0;

    h[t]=0;

    queue[rear++]=t;

    int u,v,i;

    while(front!=rear)

    {

        u=queue[front++];

        front=front%M;

        for(i=head1[u];i!=-1;i=edges1[i].next)

        {

            v=edges1[i].v;

            if(edges1[i].cap!=0||h[v]!=-1) continue;

            queue[rear++]=v;

            rear=rear%M;

            ++num[h[v]=h[u]+1];

        }

    }

}



int Maxflow(int s,int t,int n)

{

    int ans=0,i,k,x,d,u;



    BFS(s,t);



    for(i=0;i<=n;i++) curedge[i]=head1[i];

    num[n]=n;u=s;

    while(h[u]<n)

    {

        if(u==t)

        {

            d=INF+1;

            for(i=s;i!=t;i=edges1[curedge[i]].v) if(d>edges1[curedge[i]].cap)

                k=i,d=edges1[curedge[i]].cap;

            for(i=s;i!=t;i=edges1[curedge[i]].v)

            {

                x=curedge[i];

                edges1[x].cap-=d;

                edges1[x^1].cap+=d;

            }

            ans+=d;u=k;

        }

        for(i=curedge[u];i!=-1;i=edges1[i].next) if(edges1[i].cap>0&&h[u]==h[edges1[i].v]+1)

            break;

        if(i!=-1)

        {

            curedge[u]=i;

            pre[edges1[i].v]=u;

            u=edges1[i].v;

        }

        else

        {

            if(--num[h[u]]==0) break;

            curedge[u]=head1[u];

            for(x=n,i=head1[u];i!=-1;i=edges1[i].next) if(edges1[i].cap>0&&h[edges1[i].v]<x)

                x=h[edges1[i].v];

            h[u]=x+1;num[h[u]]++;

            if(u!=s) u=pre[u];

        }

    }

    return ans;

}



int visit[N];



void DFS1(int u)

{

    visit[u]=1;

    int i,v;

    for(i=head1[u];i!=-1;i=edges1[i].next)

    {

        v=edges1[i].v;

        if(edges1[i].cap>0&&!visit[v]) DFS1(v);

    }

}





int main()

{

    RD(n);

    int i,j,u,v,w,out;

    clr(head,-1);

    FOR0(i,n)

    {

        S.get();T.get();RD(w);

        u=getId(S);

        v=getId(T);

        a[u]=S; a[v]=T;

        Add(u,v,w); Add(v,u,w);

    }

    a[0]=point(0,0);

    n=0;

    FOR0(i,e) if(!b[i])

    {

        n++;area=0;

        DFS(edges[i].u,i);

        if(area<0) out=n;

    }

    S.get();T.get();

    FOR1(i,n) if(i!=out)

    {

        if(isInside(S,V[i])) s=i;

        if(isInside(T,V[i])) t=i;

    }

    clr(head1,-1);

    for(i=0;i<e;i+=2)

    {

        u=b[i];v=b[i+1];

        add(u,v,edges[i].w,i/2+1);

        add(v,u,edges[i].w,i/2+1);

    }

    PR(Maxflow(s,t,n));

    DFS1(s);

    vector<int> ans;

    FOR0(i,e1)

    {

        u=edges1[i].u;

        v=edges1[i].v;

        if(visit[u]!=visit[v]) ans.pb(edges1[i].id);

    }

    sort(ans.begin(),ans.end());

    int size=unique(ans.begin(),ans.end())-ans.begin();

    PR(size);

    FOR0(i,size) printf("%d ",ans[i]);

    puts("");

    return 0;

}

  

你可能感兴趣的:(计算)