BZOJ3571 : [Hnoi2014]画框
2014-05-14 19:35
337 查看
题目是要求最小乘积最小权匹配,
将一种方案看做一个二维点(x,y),x=a值的和,y=b值的和,所有方案中只有在下凸壳上的点才有可能成为最优解
首先要求出两端的方案l,r两个点
l就是a值的和最小的方案,
r就是b值的和最小的方案
然后递归work(l,r)即可得出所有在下凸壳上的点
work(l,r){
找到一个离lr这条直线最远的且靠近原点的点mid
如果l,mid,r构成下凸壳{
work(l,mid)
work(mid,r)
}
}
如何找mid?
把所有边边权设为(a[i],b[i])它lr直线垂线上的投影,再求普通的最小权匹配即可。
将一种方案看做一个二维点(x,y),x=a值的和,y=b值的和,所有方案中只有在下凸壳上的点才有可能成为最优解
首先要求出两端的方案l,r两个点
l就是a值的和最小的方案,
r就是b值的和最小的方案
然后递归work(l,r)即可得出所有在下凸壳上的点
work(l,r){
找到一个离lr这条直线最远的且靠近原点的点mid
如果l,mid,r构成下凸壳{
work(l,mid)
work(mid,r)
}
}
如何找mid?
把所有边边权设为(a[i],b[i])它lr直线垂线上的投影,再求普通的最小权匹配即可。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int inf=~0U>>2,N=150,M=100110; struct P{int x,y;P(){x=y=0;}P(int _x,int _y){x=_x,y=_y;}P operator-(const P&a){return P(x-a.x,y-a.y);}}L,R; inline int cross(P a,P b){return a.x*b.y-a.y*b.x;} int n,m,i,j,w ,wa ,wb ,test,ans; int u[M],v[M],c[M],co[M],coa[M],cob[M],nxt[M],t,S,T,l,r,q[M],g ,f ,d ;bool in ; inline void add(int x,int y,int z,int zo,int zoa,int zob){ u[++t]=x;v[t]=y;c[t]=z;co[t]=zo;coa[t]=zoa;cob[t]=zob;nxt[t]=g[x];g[x]=t; u[++t]=y;v[t]=x;c[t]=0;co[t]=-zo;coa[t]=-zoa;cob[t]=-zob;nxt[t]=g[y];g[y]=t; } inline bool spfa(){ memset(d,127,sizeof d);d[S]=0;in[S]=1;l=r=M>>1;q[l]=S; int x,i; while(l<=r){ int x=q[l++]; if(x==T)continue; for(i=g[x];i;i=nxt[i])if(c[i]&&co[i]+d[x]<d[v[i]]){ d[v[i]]=co[i]+d[x];f[v[i]]=i; if(!in[v[i]]){ in[v[i]]=1; if(d[v[i]]<d[q[l]])q[--l]=v[i];else q[++r]=v[i]; } } in[x]=0; } return d[T]<=inf; } inline P mincostflow(){ P p;t=1;S=0;T=n*2+1; for(i=0;i<=T;i++)g[i]=in[i]=0; for(i=1;i<=n;i++)for(j=1;j<=n;j++)add(i,j+n,1,w[i][j],wa[i][j],wb[i][j]); for(i=1;i<=n;i++)add(S,i,1,0,0,0),add(i+n,T,1,0,0,0); while(spfa())for(i=T;i!=S;i=u[f[i]])--c[f[i]],++c[f[i]^1],p.x+=coa[f[i]],p.y+=cob[f[i]]; if(p.x*p.y<ans)ans=p.x*p.y; return p; } void work(P l,P r){ P t=l-r; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)w[i][j]=cross(P(wa[i][j],wb[i][j]),t); P mid=mincostflow(); if(cross(mid-l,r-mid)>0)work(l,mid),work(mid,r); } int solve(){ ans=~0U>>1; scanf("%d",&n); for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&wa[i][j]); for(i=1;i<=n;i++)for(j=1;j<=n;j++)scanf("%d",&wb[i][j]); for(i=1;i<=n;i++)for(j=1;j<=n;j++)w[i][j]=wa[i][j]; L=mincostflow(); for(i=1;i<=n;i++)for(j=1;j<=n;j++)w[i][j]=wb[i][j]; R=mincostflow(); work(L,R); printf("%d\n",ans); } int main(){ scanf("%d",&test); while(test--)solve(); return 0; }
相关文章推荐
- bzoj3571[Hnoi2014]画框
- BZOJ 3571 [Hnoi2014]画框(最小乘积完美匹配)
- BZOJ 3571: [Hnoi2014]画框
- [BZOJ3571][Hnoi2014]画框(最小乘积匹配裸题)
- bzoj 3571: [Hnoi2014]画框
- BZOJ3571 [Hnoi2014]画框
- 【BZOJ 3571】 [Hnoi2014]画框
- [BZOJ3571][HNOI2014]画框-最小乘积KM
- bzoj3571 [Hnoi2014]画框
- [BZOJ3571][HNOI2014]画框
- [最小乘积匹配 分治 KM] BZOJ 3571 [Hnoi2014]画框
- BZOJ 3571|HNOI 2014|画框|最优匹配|计算几何
- BZOJ3571[HNOI2014]画框
- BZOJ 3571: [Hnoi2014]画框
- BZOJ 3571 [HNOI 2014] 画框 (KM算法+分治)
- BZOJ3571 [Hnoi2014]画框 【分治 + KM算法】
- 【BZOJ3571】[Hnoi2014]画框【最小乘积匹配】
- BZOJ3571 & 洛谷3236:[HNOI2014]画框——题解
- bzoj 3571: [Hnoi2014]画框 最优乘积匹配
- 【KM算法】【最大乘积生成树】[HNOI2014] bzoj3571 画框