码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2960 : 跨平面

时间:2015-12-08 01:55:02      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:

平面图求域之后增加超级根,然后建图求最小树形图即可。

 

#include<cstdio>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=3010,M=10010,inf=0x7fffffff;
int n,m,q,cnt,i,x,y,z1,z2;
struct P{
  int x,y;
  P(){}
  P(int _x,int _y){x=_x,y=_y;}
  ll operator*(const P&b){return 1LL*x*b.y-1LL*y*b.x;}
}a[N],b[M];
struct E{
  int x,y,z;double o;
  E(){}
  E(int _x,int _y,int _z){x=_x,y=_y,z=_z,o=atan2(a[y].x-a[x].x,a[y].y-a[x].y);}
}e[M];
bool del[M];int from[M];
namespace GetArea{
struct cmp{bool operator()(int a,int b){return e[a].o<e[b].o;}};
set<int,cmp>g[N];set<int,cmp>::iterator k;int i,j,q[M],t;
void work(){
  for(i=0;i<m+m;i++)if(!del[i]){
    for(q[t=1]=j=i;;q[++t]=j=*k){
      k=g[e[j].y].find(j^1);k++;
      if(k==g[e[j].y].end())k=g[e[j].y].begin();
      if(*k==i)break;
    }
    ll s=0;
    for(j=1;j<=t;j++)s+=a[e[q[j]].x]*a[e[q[j]].y],del[q[j]]=1;
    if(s<0)continue;
    for(cnt++,j=1;j<=t;j++)from[q[j]]=cnt;
  }
}
}
namespace DMST{
int n,size,pre[N],id[N],vis[N],in[N];
struct EDGE{
  int u,v,cost;
  EDGE(){}
  EDGE(int a,int b,int c):u(a),v(b),cost(c){}
}E[M];
void init(int _n){n=_n,size=0;}
void add(int u,int v,int w){E[size++]=EDGE(u,v,w);}
int dmst(int root){
  int u,v,cnt,ret=0,i;
  while(1){
    for(i=0;i<n;i++)in[i]=inf;
    for(i=0;i<size;i++){
      u=E[i].u,v=E[i].v;
      if(E[i].cost<in[v]&&u!=v)pre[v]=u,in[v]=E[i].cost;
    }
    for(cnt=in[root]=i=0;i<n;i++)id[i]=vis[i]=-1;
    for(i=0;i<n;i++){
      ret+=in[i],v=i;
      while(vis[v]!=i&&id[v]==-1&&v!=root)vis[v]=i,v=pre[v];
      if(v!=root&&id[v]==-1){
        for(u=pre[v];u!=v;u=pre[u])id[u]=cnt;
        id[v]=cnt++;
      }
    }
    if(!cnt)break;
    for(i=0;i<n;i++)if(id[i]==-1)id[i]=cnt++;
    for(i=0;v=E[i].v,i<size;i++){
      E[i].u=id[E[i].u],E[i].v=id[E[i].v];
      if(E[i].u!=E[i].v)E[i].cost-=in[v];     
    }
    n=cnt,root=id[root];
  }
  return ret;
}
void work(int _n){
  n=_n;
  int i,tot=1;
  for(i=0;i<m+m;i++)if(e[i].z)add(from[i],from[i^1],e[i].z),tot+=e[i].z;
  for(i=0;i<n-1;i++)add(n-1,i,tot);
  printf("%d",dmst(n-1)-tot);
}
}
int main(){
  scanf("%d%d",&n,&m);
  for(i=1;i<=n;i++){
    scanf("%d%d",&x,&y);
    a[i]=P(x,y);
  }
  for(i=0;i<m;i++){
    scanf("%d%d%d%d",&x,&y,&z1,&z2);
    e[i<<1]=E(x,y,z1);
    e[i<<1|1]=E(y,x,z2);
  }
  for(i=0;i<m+m;i++)GetArea::g[e[i].x].insert(i);
  GetArea::work();
  DMST::work(cnt+2);
  return 0;
}

  

BZOJ2960 : 跨平面

标签:

原文地址:http://www.cnblogs.com/clrs97/p/5027988.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!