最小乘积生成树和最小乘积最大匹配
两个知识的本质是一样的。都是每条边有k个权值(一般k为2),现在要取一个边集M使得其将所有点连通,并使每一种边权的总和的乘积最小。不同的是一个是生成树一个是匹配。
对于这一类问题,我们都可以把每种方案的x之和与y之和作为它的坐标(x,y)
要让乘积最小,那么可能的方案的坐标一定在一个下凸壳上。
首先我们求出x最小的方案的坐标,再求出y最小方案的坐标
这就是凸壳的两个端点A,B。
然后考虑分治,每次找出离直线AB最远的点C,再继续处理
要使距离最远,就是使向量AB和向量AC的叉积最大
即最大化(c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x)
即c.x*(b.y-a.y)+c.y*(a.x-b.x) -a.x*(b.y-a.y)+a.y*(b.x-a.x)
后面的一部分是常数,不用管。
就是要使c.x*(b.y-a.y)+c.y*(a.x-b.x) 最大化
对于生成树来说就用kruscal算法,匹配则是KM算法确定c,然后对AC、CB递归做同样的过程,直到找不到一个在左下的点C为止。
最小乘积生成树算法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define N 205
#define M 10100
#define inf 0x3f3f3f3f
struct Edge
{int u,v;int a,b;int c;void read(){scanf("%d%d%d%d",&u,&v,&a,&b);u++;v++;}
}e[M];
bool cmpa(const Edge &a,const Edge &b){return a.a<b.a;
}
bool cmpb(const Edge &a,const Edge &b){return a.b<b.b;
}
bool cmpc(const Edge &a,const Edge &b){return a.c<b.c;
}
struct Point{int x,y;void print(){printf("%d %d\n",x,y);}Point(int _x=0,int _y=0):x(_x),y(_y){}bool operator < (const Point &A) const{unsigned int p=x;p*=y;unsigned int q=A.x;q*=A.y;return p==q?x<A.x:p<q;}
}ans,now,mina,minb;
int f[N],n,m;
int find(int x){return f[x]==x?f[x]:f[x]=find(f[x]);
}
Point kruscal()
{int i,fa,fb;now=Point(0,0);for(int i=1;i<=n;i++)f[i]=i;for(int i=1;i<=m;i++){fa=find(e[i].u);fb=find(e[i].v);if(fa!=fb){f[fb]=fa;now.x+=e[i].a;now.y+=e[i].b;}}if(now<ans)ans=now;return now;
}
int xmul(const Point &A,const Point &B,const Point &C)
{return (C.y-A.y)*(B.x-A.x)-(C.x-A.x)*(B.y-A.y);}
void work(const Point &a,const Point &b)
{for(int i=1;i<=m;i++){e[i].c=e[i].b*(a.x-b.x)+e[i].a*(b.y-a.y);}sort(e+1,e+m+1,cmpc);Point c=kruscal();if(xmul(a,b,c)<=0)return;work(a,c);work(b,c);
}
int main()
{
// freopen("test.in","r",stdin);int i,j,k;int a,b,c;ans=Point(inf,inf);scanf("%d%d",&n,&m);for(i=1;i<=m;i++)e[i].read();sort(e+1,e+m+1,cmpa),mina=kruscal();sort(e+1,e+m+1,cmpb),minb=kruscal();work(minb,mina),ans.print();return 0;
}
最小乘积匹配:
#include<iostream>#include<cstring> #include<cstdio> #define inf 0x7fffffff struct poi{int x,y;}le,ri; int lx[75],ly[75],sla[75]; int g[75][75],a[75][75],b[75][75],f[75]; int n; bool vx[75],vy[75]; bool operator ==(poi a,poi b){return a.x==b.x&&a.y==b.y;} using namespace std; bool dfs(int x) {vx[x]=true;for (int y=1; y<=n; y++){if (!vy[y]){int t=lx[x]+ly[y]-g[x][y];if (!t){vy[y]=true;if (!f[y]||dfs(f[y])){f[y]=x;return true;}}else sla[y]=min(sla[y],t);}}return false; } poi km() {memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(f,0,sizeof(f));for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) lx[i]=max(lx[i],g[i][j]);for (int x=1; x<=n; x++){memset(sla,63,sizeof(sla));while (true){memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy));if (dfs(x)) break;int d=inf;for (int i=1; i<=n; i++) if (!vy[i]) d=min(d,sla[i]);for (int i=1; i<=n; i++){if (vx[i]) lx[i]-=d;if (vy[i]) ly[i]+=d;}}}poi ans=(poi) {0,0};for (int i=1; i<=n; i++) ans.x+=a[f[i]][i], ans.y+=b[f[i]][i];return ans; } int slove(poi l,poi r) {for(int i=1; i<=n; i++) for (int j=1; j<=n; j++) g[i][j]=a[i][j]*(r.y-l.y)+b[i][j]*(l.x-r.x);poi mid=km();if (l==mid||r==mid) return min(l.x*l.y,r.x*r.y);elsereturn min(slove(l,mid),slove(mid,r)); } int main() {int t;scanf("%d",&t);for (int z=1; z<=t; z++){scanf("%d",&n);for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) scanf("%d",&a[i][j]);for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) scanf("%d",&b[i][j]);for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) g[i][j]=-a[i][j];le=km();for (int i=1; i<=n; i++) for (int j=1; j<=n; j++) g[i][j]=-b[i][j];ri=km();printf("%d\n",slove(le,ri));} }
转载于:https://www.cnblogs.com/137033036-wjl/p/5916546.html
最小乘积生成树和最小乘积最大匹配相关推荐
- HDU5697 刷题计划 dp+最小乘积生成树
分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog ...
- P5540-[BalkanOI2011]timeismoney|最小乘积生成树【最小生成树,凸壳】
正题 题目链接:https://www.luogu.com.cn/problem/P5540 题目大意 给出nnn个点mmm条边边权是一个二元组(ai,bi)(a_i,b_i)(ai,bi),求出 ...
- Lightoj 1123 - Trail Maintenance(最小增量生成树)
题目链接 https://vjudge.net/problem/LightOJ-1123 Tigers in the Sunderbans wish to travel freely among th ...
- 最小代价生成树Prim/Kruskal(c/c++)
常用的求最小代价生成树的方法有两种:Prim算法和Kruskal算法,这两种算法都是贪心算法的应用, Prim算法 在一个无向带权图中求得最小生成树得思路是:从a顶点出发,将a放入u集合(表示已选), ...
- POJ3522Slim Span(最大边与最小边差值最小的生成树)
感谢这篇文章 本文对其代码,进行一些解释. 这道题的题意很明了.求最大边与最小边差值最小的生成树 首先,把所有的生成树都求出来是不可能的,所以,必须用别的方法. 在学习次小生成树的过程中,知道了一个最 ...
- DAG的最小路径覆盖和二分图的最大匹配
DAG的最小路径覆盖和二分图的最大匹配 DAG的最小路径覆盖是指找最小数目的互相不相交的有向路径,满足DAG的所有顶点都被覆盖. 首先给出公式:DAG的最小路径覆盖数=DAG图中的节点数-相应二分图中 ...
- TZOJ 5471: 数据结构实验--图的最小代价生成树
题目描述 求带权无向图的最小代价生成树. 输入 输入数据为多组,每组数据包含多行,第一行为2个整数n,e,n为图的顶点数,e为边数,接下来是e行,每行3个整数,前两个整数是一个顶点对,代表一条边所依附 ...
- 图论 —— 生成树 —— 最小瓶颈生成树
[概述] 所谓瓶颈生成树,即对于图 G 中的生成树树上最大的边权值在所有生成树中最小. 对于无向图来说,无向图的最小生成树一定是最小瓶颈生成树,但最小瓶颈生成树不一定是最小生成树. 因此,使用 Kru ...
- 图的绝对中心(bzoj 2180: 最小直径生成树)
2180: 最小直径生成树 Time Limit: 10 Sec Memory Limit: 259 MB Submit: 219 Solved: 105 [Submit][Status][Dis ...
最新文章
- 那位13岁就当上老板的开发者是如何炼成的?
- 聊聊 TCP 长连接和心跳那些事
- 关于Unity中的UGUI优化,你可能遇到这些问题
- Element UI——数字输入框解决方案
- when is IBASE status changed from inital to created - not answered
- (dijkstra算法+多权值)最短路径问题
- 20-40-020-安装-kafka-eagle-bin-1.3.3安装
- 怎么讲gis里的符号化_地信(GIS)方向考研~?测绘科学与技术
- OpenDaylight风头正劲,华三通信在其中大显身手
- Android(java)学习笔记51:ScrollView用法
- 【题解】二进制优化的多重背包问题
- Jquery 模板插件 jquery.tmpl.js 的使用方法(2):嵌套each循环,temp调用(使用预编译的模板缓存)...
- css 商城 两列_你需掌握的CSS知识都在这了(长文建议收藏,文末有福利)
- 室内定位技术的应用及室内定位技术的种类-新导智能
- 我喜欢邓丽君,死掉了;
- 三面蚂蚁金服成功拿到offer,成功收获美团,小米offer
- 3套CAD别墅图纸分享分析
- 今日学习之Javascript
- Android Studio连接安卓手机驱动
- Web Storage知识点梳理,模拟后台管理系统部分功能