BZOJ 2960 跨平面 对偶图+朱刘算法

题目大意:给定一张平面图,求对偶图的最小树形图

这题TM考了我两遍!!两遍!!我拿了两遍MST的60分!

世界你赢了 你逼着我学了朱刘算法233

#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 3030
#define INF 0x3f3f3f3f
using namespace std;
struct Point{
	int x,y;
	Point() {}
	Point(int _,int __):x(_),y(__) {}
	friend istream& operator >> (istream &_,Point &p)
	{
		scanf("%d%d",&p.x,&p.y);
		return _;
	}
	friend Point operator - (const Point &p1,const Point &p2)
	{
		return Point(p1.x-p2.x,p1.y-p2.y);
	}
	friend double Arctan2(const Point &p)
	{
		return atan2(p.y,p.x);
	}
}points[M];
struct List{
	List *another;
	int to,len,belong;
	double alpha;
	List() {}
	List(int _,int __,double ___):
		another(0x0),to(_),len(__),belong(0),alpha(___) {}
};
int n,m,cnt=1;
vector<List*> a[M];
bool Compare(const List *x,const List *y)
{
	return x->alpha < y->alpha ;
}
void Add(int x,int y,int t1,int t2)
{
	if(!t1) t1=INF;
	if(!t2) t2=INF;

	Point p=points[y]-points[x];

	List *temp1=new List(y,t1,Arctan2(p));
	List *temp2=new List(x,t2,Arctan2(Point(0,0)-p));

	temp1->another=temp2;
	temp2->another=temp1;

	a[x].push_back(temp1);
	a[y].push_back(temp2);
}
void DFS(int x,List *from,int aim)
{
	from->belong=cnt;

	if(x==aim)
		return ;

	vector<List*>::iterator it=lower_bound(a[x].begin(),a[x].end(),from->another,Compare);
	it++;if(it==a[x].end()) it=a[x].begin();

	DFS((*it)->to,*it,aim);
}
namespace Dual_Graph{
	struct edge{
		int x,y,z;
		edge() {}
		edge(int _,int __,int ___):
			x(_),y(__),z(___) {}
	}edges[100100];
	int n,m;
	void Add(int x,int y,int z)
	{
		++m;
		edges[m].x=x;
		edges[m].y=y;
		edges[m].z=z;
	}
	int DMST()
	{
		static int f[M],from[M],v[M],T;
		static bool deleted[M];
		int i,j,re=0;
		while(1)
		{
			memset(f,0x3f,sizeof f);
			memset(from,0,sizeof from);
			for(i=1;i<=m;i++)
				if(f[edges[i].y]>edges[i].z)
				{
					f[edges[i].y]=edges[i].z;
					from[edges[i].y]=edges[i].x;
				}
			for(i=2;i<=n;i++)
				if(!deleted[i])
					if(f[i]==INF)
						return -1;
			memset(v,0,sizeof v);
			for(i=2;i<=n;i++)
				if(!deleted[i])
				{
					for(++T,j=i;j!=1&&!v[j];j=from[j])
						v[j]=T;
					if(v[j]==T)
						break;
				}
			if(i==n+1)
			{
				for(i=2;i<=n;i++)
					if(!deleted[i])
						re+=f[i];
				return re;
			}
			memset(v,0,sizeof v);
			i=j;do{
				i=from[i];
				re+=f[i];
				v[i]=true;
				deleted[i]=true;
			}while(i!=j);
			deleted[j]=false;
			int cnt=0;
			for(i=1;i<=m;i++)
			{
				if(!v[edges[i].x]&&!v[edges[i].y])
					edges[++cnt]=edges[i];
				else if(v[edges[i].x]&&v[edges[i].y])
					continue;
				else if(v[edges[i].x])
					edges[++cnt]=edge(j,edges[i].y,edges[i].z);
				else
					edges[++cnt]=edge(edges[i].x,j,edges[i].z-f[edges[i].y]);
			}
			m=cnt;
		}
	}
}
int main()
{
	//freopen("square.in","r",stdin);
	//freopen("square.out","w",stdout);
	int i,x,y,t1,t2;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		cin>>points[i];
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&t1,&t2);
		Add(x,y,t1,t2);
	}
	for(i=1;i<=n;i++)
		sort(a[i].begin(),a[i].end(),Compare);
	for(x=1;x<=n;x++)
	{
		vector<List*>::iterator it;
		for(it=a[x].begin();it!=a[x].end();it++)
			if(!(*it)->belong)
				++cnt,DFS((*it)->to,*it,x);
	}
	for(x=1;x<=n;x++)
	{
		vector<List*>::iterator it;
		for(it=a[x].begin();it!=a[x].end();it++)
			if((*it)->len!=INF)
				Dual_Graph::Add((*it)->another->belong,(*it)->belong,(*it)->len);
	}
	Dual_Graph::n=cnt;
	for(i=2;i<=cnt;i++)
		Dual_Graph::Add(1,i,0x1010101);
	cout<<Dual_Graph::DMST()-0x1010101<<endl;
	return 0;
}
时间: 2024-10-16 08:24:18

BZOJ 2960 跨平面 对偶图+朱刘算法的相关文章

hdu2121 - Ice_cream’s world II(朱刘算法,不固定根)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2121 题目意思大概是要你在一些城市中选一个做首都 , 要求首都都能到其他城市 , 道路花费要最少 , 且道路都是单向的 , 这个时候就要用到最小树形图算法了 , 而且是不固定根. 不定根就是加一个虚根(原本不存在的点) , 可以让这个虚根到每个点的距离大于原本所有点连接的道路花费之和sum , 然后计算出的结果减去sum,如果比sum还大就可以认为通过这个虚拟节点我们连过原图中两个点,即原图是不连通

UVA-11865 Stream My Contest (朱-刘 算法+二分)

题目大意:有一张n个顶点,m条边的有向图,根节点为0.每条边有两个权值,一个是费用c,一个是长度b.问在总费用不超过cost的情况下选出若干条边,使得n个点连通时的边的最短长度的最大值是多少. 题目分析:如果已知这个最短距离的最大值d,则问题就变成了:用长度不小于d的边能否构成一个总权值不大于cost的最小树形图.因此,二分枚举d,用朱-刘 算法判断即可. 代码如下: # include<iostream> # include<cstdio> # include<vector

【朱-刘算法】【最小树形图】hdu6141 I am your Father!

题意:给你一张带权有向图,让你求最大树形图.并在此前提下令n号结点父亲的编号最小. 比赛的时候套了个二分,TLE了. 实际上可以给每个边的权值乘1000,对于n号结点的父边,加上(999-父结点编号)大小的权值,这样即可保证最大树形图的前提下,n号结点父亲的编号最小. 网上找了个朱-刘算法的板子,把边权取负就能跑最大树形图了. #include <cstdio> #include <string> #include <cstring> #define MAXN 1005

AIZU AOJ 2309 Vector Compression 最小树形图(朱—刘算法)

题意简述:给定若干个相同维度的向量,寻找一种排序方法,使得所有向量的表示长度总和最低. 所谓表示长度为(Aj-r*Ai)^2,其中i<j  数据范围:向量总数和维度均小于100 思路:(1)首先Ai和Aj确定后,最小表示长度是可以在线性时间计算出来的.使用简单的二次函数分析方法即可. (2)上述可以得出任意两向量之间的距离,即为图中的边,于是问题可以转化为有向图的"最小树形图",i到j的有向边权值即为用Aj表示Ai的最小表示长度. (3)朱-刘算法简述: 首先对除根以外的点选择一

UVa11183 Teen Girl Squad, 最小树形图,朱刘算法

Teen Girl Squad Input: Standard Input Output: Standard Output You are part of a group of n teenage girls armed with cellphones. You have some news you want to tell everyone in the group. The problem is that no two of you are in the same room, and you

POJ--3164--Command Network【朱刘算法】最小树形图

链接:http://poj.org/problem?id=3164 题意:告诉n个点坐标,m条边表示两个点之间有路.从1点開始建立一个有向图最小生成树. 朱刘算法模板题 ========================== 切割线之下摘自user_id=Sasuke_SCUT" style="color:rgb(202,0,0); text-decoration:none; font-family:Arial; font-size:14px; line-height:26px"

POJ - 3164 Command Network(朱刘算法)

题目大意:有N个点,M条有向边.现在要求你以1为根,构造出一棵最小生成树,问这棵最小生成树能否被构造出来,如果可以,总权值是多少 解题思路:朱刘算法的裸题,我只想吐槽一下POJ,用的是double型的,输出时是%.2lf,结果是WA 换成了%.2f就A了..这什么情况,白白花费了1个多小时去调错.. #include <cstdio> #include <cstring> #include <cmath> using namespace std; #define N 1

HDU - 2121 Ice_cream’s world II(朱刘算法+虚根)

题目大意:给你N个点,M条有向边,问以哪个点为根结点时,能使最小生成树总权值达到最小,输出总权值和根. 如果构不成最小生成树,另外输出 解题思路:这题很巧妙,暴力枚举的话,肯定TLE,所以,这题就需要点技巧了 可以设一个虚根,虚根连接每一个点,权值为所有边的总权值+1.接着,以虚根为根,跑朱刘算法. 跑出结果后,要判断一下,如果最小生成树的总权值比2 * (所有边的总权值+1)还要大,表示虚根至少和两个点相连了,这样最小生成树就是棵假的最小生成树了,因为至少有两个点入度为0了 得到结果时要怎么找

poj 3164 最小树形图(朱刘算法)

朱刘算法模板题 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define INF 1<<30 using namespace std; int n,m; struct node { double x,y; }nod[110<<1]; double in[110<<1