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

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值