标签:le 匹配 mat int sum mine638 out
题意:给定平面上$n$个点$P_{i}(x_{i},y_{i})$和$n$个向量$(u_{i},v_{i})$,构造排列$\{p_{i}\}$满足——
记$P'_{i}(x_{i}+u_{p_{i}},y_{i}+v_{p_{i}})$,要求$\forall (i,j),d(P_{i},P_{j})\le d(P'_{i},P'_{j})$并最大化$\sum_{i,j}d^{2}(P'_{i},P'_{j})$
$1\le n\le 500$,$|x_{i}|,|y_{i}|,|u_{i}|,|v_{i}|\le 10^{4}$
忽略条件,将最大化的式子展开(以$x$坐标为例),即
$$
\sum_{i,j}(x_{i}-x_{j})^{2}+\sum_{i,j}(u_{p_{i}}-u_{p_{j}})^{2}-2\sum_{i,j}(x_{i}u_{p_{j}}+x_{j}u_{p_{i}})+2\sum_{i,j}(x_{i}u_{p_{i}}+x_{j}u_{p_{j}})
$$
显然前三项均为常数,最后一项等价于最大化$\sum_{i=1}^{n}x_{i}u_{p_{i}}$
换言之,若$(i,j)$匹配的价值为$x_{i}u_{j}+y_{i}v_{j}$,则问题即求最大权匹配
同时,若该匹配对$(i,j)$不满足,将条件的式子展开,即
$$
(u_{p_{i}}-u_{p_{j}})^{2}-2(x_{i}u_{p_{j}}+x_{j}u_{p_{i}})+2(x_{i}u_{p_{i}}+x_{j}u_{p_{j}})+...<0\\
(x_{i}u_{p_{i}}+x_{j}u_{p_{j}})-(x_{i}u_{p_{j}}+x_{j}u_{p_{i}})+...<-\frac{(u_{p_{i}}-u_{p_{j}})^{2}+...}{2}\le 0
$$
其中$...$表示$y$坐标对应的式子,进而即交换$p_{i}$和$p_{j}$后权值更大,矛盾
使用KM算法或势能dijkstra优化费用流均可做到$o(n^{3})$,但后者常数较大,无法通过
KM算法
为了使得两部点数相同且为完全图,进行如下处理(本题中已满足)
在点数较少的一部中加入若干个点使点数与另一部相同,将不存在的边权设为$0$
记$e_{(u,v)}$为边权,称一组权值$\{w_{i}\}$合法当且仅当$\forall (u,v),e_{(u,v)}\le w_{u}+w_{v}$
对于合法权值$\{w_{i}\}$,称"相等子图"为仅保留$e_{(u,v)}=w_{u}+w_{v}$的边时所得到的图
性质1:若"相等子图"存在完美匹配,则该匹配即为(原图)最大权匹配
根据条件,任意匹配权值均$\le \sum w$,而该完美匹配恰取到$\sum w$,显然最大
为了方便,初始令左部点权值为最大出边边权,右部点权值为$0$
求"相等子图"的最大匹配,当某个点无法匹配时,考虑对应的交错树:
将左部分为$L_{in}$和$L_{out}$,分别表示在交错树中和不在交错树中,右部同理
性质2:$L_{out}$和$R_{in}$间不存在匹配边,$L_{in}$和$R_{out}$间不存在边
根据交错树的性质,若这些边存在即会被搜索,与"不在交错树中"矛盾
在此基础上,考虑将$L_{in}$中所有点权值$-a$,$R_{in}$中所有点权值$+a$
此时,影响即两点:1.$L_{out}$和$R_{in}$间的边被删除;2.$L_{in}$和$R_{out}$间新增若干条边
另外,为了保证合法性,显然$a$即取最小的能在$L_{in}$和$R_{out}$间新增边的值即可
关于实现,需要对右部的点$v$维护$\min_{u\in L_{in}}w_{u}+w_{v}-e_{(u,v)}$以及取到最小值的$u$
在$u$加入$L_{in}$和点权修改时,显然均可维护,且再次搜索时直接从这类$v$出发即可
时间复杂度为$o(n^{3})$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 505 4 #define ll long long 5 #define y1 y11 6 int n,T,x1[N],y1[N],x2[N],y2[N],e[N][N],w[N<<1]; 7 int vis[N],mn[N],pos[N],from[N],mat[N<<1];queue<int>q; 8 void get_mat(int k){ 9 memset(vis,0,sizeof(vis)); 10 memset(mn,0x3f,sizeof(mn)); 11 while (!q.empty())q.pop(); 12 q.push(k),vis[k]=1; 13 while (1){ 14 while (!q.empty()){ 15 int k=q.front();q.pop(); 16 for(int i=1;i<=n;i++){ 17 if (mn[i]>w[k]+w[i+n]-e[k][i]){ 18 mn[i]=w[k]+w[i+n]-e[k][i],pos[i]=k; 19 } 20 if (e[k][i]==w[k]+w[i+n]){ 21 if (!mat[i+n]){ 22 from[i]=k; 23 while (i)mat[i+n]=from[i],swap(i,mat[from[i]]); 24 return; 25 } 26 if (!vis[mat[i+n]])from[i]=k,q.push(mat[i+n]),vis[mat[i+n]]=1; 27 } 28 } 29 } 30 int Mn=0x3f3f3f3f; 31 for(int i=1;i<=n;i++) 32 if (!vis[mat[i+n]])Mn=min(Mn,mn[i]); 33 for(int i=1;i<=n;i++){ 34 if (vis[i])w[i]-=Mn; 35 if (!vis[mat[i+n]])mn[i]-=Mn; 36 else w[i+n]+=Mn; 37 } 38 for(int i=1;i<=n;i++) 39 if ((!vis[mat[i+n]])&&(!mn[i])){ 40 from[i]=pos[i]; 41 if (!mat[i+n]){ 42 while (i)mat[i+n]=from[i],swap(i,mat[from[i]]); 43 return; 44 } 45 q.push(mat[i+n]),vis[mat[i+n]]=1; 46 } 47 } 48 } 49 int main(){ 50 scanf("%d",&n),T=(n<<1)+1; 51 for(int i=1;i<=n;i++)scanf("%d%d",&x1[i],&y1[i]); 52 for(int i=1;i<=n;i++)scanf("%d%d",&x2[i],&y2[i]); 53 for(int i=1;i<=n;i++) 54 for(int j=1;j<=n;j++){ 55 e[i][j]=x1[i]*x2[j]+y1[i]*y2[j]; 56 w[i]=max(w[i],e[i][j]); 57 } 58 for(int i=1;i<=n;i++)get_mat(i); 59 printf("Yes\n"); 60 for(int i=1;i<=n;i++)printf("%d ",mat[i]); 61 return 0; 62 }View Code
标签:le,匹配,mat,int,sum,mine638,out 来源: https://www.cnblogs.com/PYWBKTDA/p/16335172.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。