[bzo2395][最小乘积生成树]Timeismoney

版权声明:蒟蒻写的..能不能吱一声呀 https://blog.csdn.net/Rose_max/article/details/83627056

Description

有n个城市(编号从0…n-1),m条公路(双向的),从中选择n-1条边,使得任意的两个城市能够连通,一条边需要的c的费用和t的时间,定义一个方案的权值v=n-1条边的费用和*n-1条边的时间和,你的任务是求一个方案使得v最小

Input

第一行两个整数n,m,接下来每行四个整数a,b,c,t,表示有一条公路从城市a到城市b需要t时间和费用c

Output

仅一行两个整数sumc,sumt,(sumc表示使得v最小时的费用和,sumc表示最小的时间和)
如果存在多个解使得sumc*sumt相等,输出sumc最小的

Sample Input

5 7

0 1 161 79

0 2 161 15

0 3 13 153

扫描二维码关注公众号,回复: 4337739 查看本文章

1 4 142 183

2 4 236 80

3 4 40 241

2 1 65 92

Sample Output

279 501

HINT

【数据规模】

1<=N<=200

1<=m<=10000

0<=a,b<=n-1

0<=t,c<=255

有5%的数据m=n-1

有40%的数据有t=c

对于100%的数据如上所述

题解

最小乘积生成树
如果把每种方案看成二维平面上的一个点,横坐标看作 c \sum c ,纵坐标看作 t \sum t
答案会在这些点的下凸包上
先找出两个点 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A(x1,y1),B(x2,y2) ,满足在所有方案中 x 1 x1 最小以及 y 2 y2 最小
那么大概的感觉就是个这样的东西
在这里插入图片描述
每次求出一个点 C ( x 3 , y 3 ) C(x3,y3) ,满足三角形 A B C ABC 面积最大
根据叉积不难得到这个三角形的面积是
( x 1 x 3 ) ( y 2 y 3 ) ( x 2 x 3 ) ( y 1 y 3 ) (x1-x3)(y2-y3)-(x2-x3)(y1-y3)
化一下就知道是
x 3 ( y 1 y 2 ) + y 3 ( x 2 x 1 ) + x 1 y 2 x 2 y 1 x3(y1-y2)+y3(x2-x1)+x1y2-x2y1
后面是常数可以不用管
于是每条边可以变为 c ( y 1 y 2 ) + t ( x 2 x 1 ) c*(y1-y2)+t*(x2-x1)
显然可以知道在该情况下叉积为负,求一个MST就好了
显然如果最后叉积为正就找不到这个 C C 点了
求出来后可以知道三角形 A B C ABC 内的点均没有贡献,递归 A C AC C B CB 求解
复杂度大约是 n n 2 \sqrt n*n^2 的吧…
偷懒写了kruskal

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(LL x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(LL x){write(x);puts("");}
struct pt
{
	int a,b;
	pt(){a=b=0;}
	pt(int _a,int _b){a=_a;b=_b;}
};
struct node
{
	int x,y;
	int a,b;
}w[11000];int n,m,cnt;
int fa[210];
int findfa(int x){return fa[x]==x?fa[x]:fa[x]=findfa(fa[x]);}
void clear(){for(int i=1;i<=n;i++)fa[i]=i;cnt=n;}
bool cmp1(node n1,node n2){return n1.a<n2.a;}
bool cmp2(node n1,node n2){return n1.b<n2.b;}
int s1,s2,a1,a2;
LL multi(pt p0,pt p1,pt p2)
{
	int u1,u2,v1,v2;
	u1=p1.a-p0.a;u2=p2.a-p0.a;
	v1=p1.b-p0.b;v2=p2.b-p0.b;
	return (LL)u1*v2-(LL)u2*v1;
}
bool cmp3(node n1,node n2){return (LL)n1.a*s2+n1.b*s1<(LL)n2.a*s2+n2.b*s1;}
void query(pt u1,pt u2)
{
	pt u3;
	s1=u2.a-u1.a;s2=u1.b-u2.b;
	clear();sort(w+1,w+1+m,cmp3);
	for(int i=1;i<=m;i++)
	{
		int p=findfa(w[i].x),q=findfa(w[i].y);
		if(p!=q)fa[p]=q,u3.a+=w[i].a,u3.b+=w[i].b,cnt--;
		if(cnt==1)break;
	}
	if(multi(u3,u1,u2)>=0)return ;
	if((LL)u3.a*u3.b<(LL)a1*a2)a1=u3.a,a2=u3.b;
	else if((LL)u3.a*u3.b==(LL)a1*a2&&a1>u3.a)a1=u3.a,a2=u3.b;
//	ans=min(ans,u3.a*u3.b);
	query(u1,u3);query(u3,u2);
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=m;i++)w[i].x=read()+1,w[i].y=read()+1,w[i].a=read(),w[i].b=read();
	pt u1,u2;
	clear();sort(w+1,w+1+m,cmp1);
	for(int i=1;i<=m;i++)
	{
		int p=findfa(w[i].x),q=findfa(w[i].y);
		if(p!=q)fa[p]=q,u1.a+=w[i].a,u1.b+=w[i].b,cnt--;
		if(cnt==1)break;
	}
	clear();sort(w+1,w+1+m,cmp2);
	for(int i=1;i<=m;i++)
	{
		int p=findfa(w[i].x),q=findfa(w[i].y);
		if(p!=q)fa[p]=q,u2.a+=w[i].a,u2.b+=w[i].b,cnt--;
		if(cnt==1)break;
	}
	if((LL)u1.a*u1.b<=(LL)u2.a*u2.b)a1=u1.a,a2=u1.b;
	else a1=u2.a,a2=u2.b;
//	ans=min(u1.a*u1.b,u2.a*u2.b);
	query(u1,u2);
	pr1(a1);pr2(a2);
	return 0;	
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/83627056