bzoj-2960 跨平面

題意:

給出一個平面圖,每條邊從不同方向各有一個跨越代價(或者不能跨越);

求一個最小總跨越代價,使從某個平面區域能跨越到所有其他區域;

即在此平面圖的對偶圖上求最小樹形圖;

平面圖中點數<=3000,區域數<=1000,跨越代價<=100;


題解:

實際上這是兩道裸題。。。然後我作死的學了兩種算法;


首先是平面圖轉對偶圖:

首先將無向邊拆成兩條單向邊,按順/逆時針掛在端點上;

每一次從一條沒有經過的單向邊出發,深搜;

深搜每到達一個點,我們都找到從來的邊順/逆時針旋轉,得到的第一個邊繼續深搜,搜到最開始的點時停止;

這個過程中因爲每次都是找第一條邊來搜,所以這個區域一定不包含其他區域的;

然後記錄該區域編號,深搜回溯時將來時的每條邊都記錄這個編號;

搜索次數與平面區域數有關,每條邊只會被搜索一次,而平面區域數與邊數最多與頂點數同級;

所以如果使用二分查找,時間複雜度是O(nlogn)的吧。。。

(然而我這麼懶當然寫的是O(n^2)暴力)


轉化成對偶圖之後,就是應用最小樹形圖的朱劉算法了;

這個網上講的似乎都很詳細?

需要注意的地方就是找環的時候小心一些,不要將環外面的樹也算進去;

當然了,這道題沒有自環,不用做預處理;

時間複雜度是O(nm);


代碼:


#include<queue>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
namespace Graph
{
	#define N 2100
	#define M 50000
	int X[M],Y[M],val[M],ce;
	int next[M],to[M],head[N],cnt,tot;
	int in[N],fa[N];
	int n;
	bool vis[N],inc[N];
	void add(int x,int y,int v)
	{
		Y[++ce]=y;
		X[ce]=x;
		val[ce]=v;
	}
	void addedge(int x,int y)
	{
		to[++cnt]=y;
		next[cnt]=head[x];
		head[x]=cnt;
	}
	int dfs(int x)
	{
		inc[x]=1;
		if(inc[fa[x]])
		{
			tot+=in[x];
			return fa[x];
		}
		else
		{
			int temp=dfs(fa[x]);
			if(temp&&x!=temp)
			{
				tot+=in[x];
				return temp;
			}
			else if(x==temp)
			{
				tot+=in[x];
				return 0;
			}
		}
		inc[x]=0;
		return 0;
	}
	int check()
	{
		for(int i=0;i<=n;i++)
			if(!vis[i])
				in[i]=0x3f3f3f3f,head[i]=0,inc[i]=1;
		for(int i=1;i<=ce;i++)
		{
			if(!vis[X[i]]&&!vis[Y[i]])
			{
				if(in[Y[i]]>val[i])
				{
					in[Y[i]]=val[i];
					fa[Y[i]]=X[i];
				}
			}
		}
		int ret=0;
		for(int i=1;i<=n;i++)
			if(!vis[i])
				ret+=in[i];
		cnt=0;
		for(int i=1;i<=n;i++)
			if(!vis[i])
				addedge(fa[i],i);
		static queue<int>q;
		q.push(0);
		while(!q.empty())
		{
			int x=q.front();
			q.pop();
			inc[x]=0;
			for(int i=head[x];i;i=next[i])
			{
				q.push(to[i]);
			}
		}
		for(int i=0;i<=n;i++)
			if(!vis[i]&&inc[i])
			{
				memset(inc,0,sizeof(inc[0])*(n+1));
				dfs(i);
				return -1;
			}
		return ret;
	}
	int slove()
	{
		int ans,sum,i;
		for(i=1,sum=0;i<=ce;i++)
		{
			sum+=val[i];
		}
		for(i=1;i<=n;i++)
			add(0,i,sum+1);
		tot=0;
		while((ans=check())==-1)
		{
			for(i=1;i<=ce;i++)
			{
				if(inc[X[i]]&&!vis[Y[i]]&&!inc[Y[i]])
				{
					X[i]=n+1;
				}
				else if(!vis[X[i]]&&!inc[X[i]]&&inc[Y[i]])
				{
					val[i]-=in[Y[i]];
					Y[i]=n+1;
				}
			}
			for(i=0;i<=n;i++)
			{
				if(inc[i])
					vis[i]=1,inc[i]=0;
			}
			n++;
		}
		return ans+tot-sum-1;
	}
	#undef N
	#undef M
}
namespace Plane
{
	#define N 3100
	#define M 15000
	struct Point
	{
		int x,y;
		Point(){}
		Point(int _,int __):x(_),y(__){}
	}a[N];
	struct Line
	{
		int x,y,num;
		bool v;
		double alpha;
		friend bool operator <(Line a,Line b)
		{
			return a.alpha<b.alpha;
		}
	}l[M];
	int next[M],to[M],num[M],head[N],ce;
	bool v[M];
	int	val[M][2],X[M][2];
	bool vis[N];
	void add(int x,int y,int tnum,bool tv)
	{
		to[++ce]=y;
		v[ce]=tv;
		num[ce]=tnum;
		next[ce]=head[x];
		head[x]=ce;
	}
	int dfs(int x,int pre)
	{
		if(vis[x])	return ++Graph::n;
		for(int i=head[x];i;i=next[i])
		{
			if(to[i]==pre)
			{
				i=next[i];
				if(i)
					return X[num[i]][v[i]]=dfs(to[i],x);
				else
					return X[num[head[x]]][v[head[x]]]=dfs(to[head[x]],x);
			}
		}
		return 0;
	}
	void slove()
	{
		int n,m,i,x,y;
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&a[i].x,&a[i].y);
		}
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d%d",&x,&y,&val[i][0],&val[i][1]);
			l[i+i-1].x=x,l[i+i-1].y=y,l[i+i-1].num=i,l[i+i-1].v=0;
			l[i+i-1].alpha=atan2(a[y].y-a[x].y,a[y].x-a[x].x);
			l[i+i].x=y,l[i+i].y=x,l[i+i].num=i,l[i+i].v=1;
			l[i+i].alpha=atan2(a[x].y-a[y].y,a[x].x-a[y].x);
		}
		sort(l+1,l+m+m+1);
		for(i=1;i<=m+m;i++)
		{
			add(l[i].x,l[i].y,l[i].num,l[i].v);
		}
		for(x=1;x<=n;x++)
		{
			vis[x]=1;
			for(i=head[x];i;i=next[i])
			{
				if(!X[num[i]][v[i]])
					X[num[i]][v[i]]=dfs(to[i],x);
			}
			vis[x]=0;
		}
		for(i=1;i<=m;i++)
		{
			if(val[i][0])
				Graph::add(X[i][0],X[i][1],val[i][0]);
			if(val[i][1])
				Graph::add(X[i][1],X[i][0],val[i][1]);
		}
	}
	#undef N
	#undef M
}
int main()
{
	Plane::slove();
	printf("%d\n",Graph::slove());
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章