【BZOJ2965】保护古迹 平面图转对偶图,暴力,网络流

#include <stdio.h>
int main()
{
	puts("转载请注明出处谢谢");
	puts("http://blog.csdn.net/vmurder/article/details/43199045");
}

题意:自己看去吧。

题解:如果不考虑这道题的某些小数据范围,

那么正解应该是:

首先平面图转对偶图,

然后扫描线处理名胜古迹

过程中运用到邪恶的平衡树(就算是set也依然恶心)

或者用神奇方法Ⅰ判断(cheat)一个名胜古迹在哪些域里面

[注: 域]:就是一些线段围起来的一块啦。

然后用神奇方法Ⅱ(cheat<<1)算出保护i个时是哪i个

然后是裸最小割噗。

所幸:

一、

名胜古迹最多10个,这样我们就可以暴力判断一个名胜古迹在哪些域里了

(枚举域的每一条边,然后判断onleft( 点 , 有向边 ))

但是,即使这样,我们仍然需要神奇方法Ⅰ:

一个大多边形中间套一个小多边形,导致一个域是环形怎么办啊?!!!

一个多边形特么地是一个凹多边形,导致某名胜古迹在某条边的右边,但是依然在域里怎么办啊?!!!

所幸:

二、

题目中说“简单多边形”,

虽然简单多边形世上早有定义,但是显然出题人有解释权,可以解释没有这两种情况。。。

然后那个保护i个时需要保护的是哪些就无所谓啦~~~

暴搜一下又不是不能过~~

240ms又强又厉害(而且我还是渣常数呢!)

代码:

#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 300
#define M 50000
#define eps 1e-9
#define inf 0x3f3f3f3f
const double pi=acos(-1.0);
using namespace std;

struct Point
{
	int x,y;
	void read(){scanf("%d%d",&x,&y);}
	Point(int _x=0,int _y=0):x(_x),y(_y){}
}point[N],palace[N];
struct Line
{
	int u,v,next;
	int crs,cost;
	double ang;
	Line(int _u=0,int _v=0,int _cost=0):u(_u),v(_v),cost(_cost)
	{
		ang=atan2(point[v].y-point[u].y,point[v].x-point[u].x);
		if(ang<eps)ang+=2*pi;
		next=crs=0;
	}
}line[M];
bool cmp_eid(int a,int b){return line[a].ang-line[b].ang<eps;}
struct D
{
	int eid[105],m;
	void sort_the_eid(){sort(eid+1,eid+m+1,cmp_eid);}
}place[N];

struct KSD
{
	int v,len,il,next;
	void init(){len=il;}
}e[M];
int head[N],cnt;
inline void add(int u,int v,int len)
{
	e[++cnt].v=v;
	e[cnt].len=e[cnt].il=len;
	e[cnt].next=head[u];
	head[u]=cnt;
}

int s,t,d[N];
queue<int>q;
bool bfs()
{
	while(!q.empty())q.pop();
	memset(d,0,sizeof d);

	int i,u,v;
	q.push(s),d[s]=1;
	while(!q.empty())
	{
		u=q.front(),q.pop();
		for(i=head[u];i;i=e[i].next)if(e[i].len)
		{
			if(!d[v=e[i].v])
			{
				d[v]=d[u]+1;
				if(v==t)return 1;
				q.push(v);
			}
		}
	}
	return 0;
}
int dinic(int x,int flow)
{
	if(x==t)return flow;
	int remain=flow,i,v,k;
	for(i=head[x];i&&remain;i=e[i].next)
	{
		if(d[v=e[i].v]==d[x]+1&&e[i].len)
		{
			k=dinic(v,min(remain,e[i].len));
			if(!k)d[v]=0;
			e[i].len-=k,e[i^1].len+=k;
			remain-=k;
		}
	}
	return flow-remain;
}

int n,m,p;

int stk[M],top,tot;
void dfs_trans(int now,int end)
{
	stk[++top]=now;
	int id=line[now^1].next;
	if(id!=end)dfs_trans(id,end);
}
inline long long xmul(Point a,Point b,Point c)
{return (long long)(b.x-a.x)*(c.y-a.y)-(long long)(b.y-a.y)*(c.x-a.x);}
inline bool on_left(Point a,Line b)
{return xmul(a,point[b.u],point[b.v])>eps;}
bool check_t()
{
	long long sum=0;
	for(int i=1;i<=top;i++)sum+=xmul(Point(0,0),point[line[stk[i]].u],point[line[stk[i]].v]);
	return sum<eps;
}
bool check_p(int id)
{
	for(int i=1;i<=top;i++)
		if(!on_left(palace[id],line[stk[i]]))
			return 0;
	return 1;
}
int yc;
void build_map()
{
	int i,j,k;
	int a,b,c;
	scanf("%d%d%d",&p,&n,&m);
	cnt=1;
	for(i=1;i<=p;i++)palace[i].read();
	for(i=1;i<=n;i++)point[i].read();
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		line[++cnt]=Line(a,b,c);
		place[a].eid[++place[a].m]=cnt;
		line[++cnt]=Line(b,a,c);
		place[b].eid[++place[b].m]=cnt;
	}
	for(i=1;i<=n;i++)
	{
		place[i].sort_the_eid();
		if(!place[i].m)continue;
		for(j=2;j<=place[i].m;j++)
		{
			k=place[i].eid[j];
			line[k].next=place[i].eid[j-1];
		}
		line[place[i].eid[1]].next=place[i].eid[j-1];
	}
	k=cnt,cnt=1;
	tot=s=0;
	for(i=2;i<=k;i++)if(!line[i].crs)
	{
		dfs_trans(i,i);
		tot++;
		if(check_t())t=tot;
		else {
			for(j=1;j<=p;j++)if(check_p(j))
			{
				add(s,tot,0);
				add(tot,s,0);
			}
		}
		while(top)
		{
			int de=stk[top--];
			line[de].crs=tot;
		}
	}
	yc=cnt;
	for(i=2;i<=k;i+=2)
	{
		add(line[i].crs,line[i^1].crs,line[i].cost);
		add(line[i^1].crs,line[i].crs,line[i].cost);
	}
	return ;
}
bool vis[N];
int ans,maxflow;
void dfs_build(int dep,int deep,int now)
{
	int i;
	if(dep>deep)
	{
		for(i=1;i<=p;i++)
		{
			if(vis[i])e[i<<1].len=e[i<<1|1].len=inf;
			else e[i<<1].len=e[i<<1|1].len=0;
		}
		for(i=p*2+2;i<=cnt;i++)e[i].init();
		maxflow=0;
		while(bfs())maxflow+=dinic(s,inf);
		ans=min(ans,maxflow);
		return ;
	}
	int uplimit=p-deep+dep;
	for(i=now;i<=uplimit;i++)
	{
		vis[i]=1;
		dfs_build(dep+1,deep,i+1);
		vis[i]=0;
	}
	return ;
}

int main()
{
//	freopen("test.in","r",stdin);
	build_map();
	for(int i=1;i<=p;i++)
	{
		ans=inf;
		dfs_build(1,i,1);
		printf("%d\n",ans);
	}
	return 0;
}
时间: 2024-10-05 03:15:39

【BZOJ2965】保护古迹 平面图转对偶图,暴力,网络流的相关文章

BZOJ 2965 保护古迹 平面图转对偶图+最小割

题目大意:给出一个平面图,这个平面图中分布着一些点,可以用平面图中的边将一些点围住,问围住k个点的最小花费是多少. 思路:这题重点是平面图转对偶图.做法不难理解.先将所有的边拆成两条,枚举所有的边,若这个边没有被标记过,那么就对这条边进行搜索,弄出来以这个边为一边的平面区域,可以顺时针或者逆时针.将所有边挂在这条边的起点上,在所有点上按照每条边的极角排序,每次找的时候找大于(或小于)当前边的反向边的第一条边作为搜索的下一条边.直到回到最开始的点.找边的过程中记录面积,判断面积的正负来判断这个平面

BZOJ2965 : 保护古迹

首先要将这个图连通,方法是通过扫描线+set求出每个连通块最高的点上方的第一条边,然后向交点连边. 然后把边拆成两条双向边,每次找到一条没走过的边,找到极角排序后它的反向边的后继,直到回到这条边. 根据叉积可以求出面积,如果面积非负,那么就说明找到了一个封闭区域. 然后再进行一次扫描线,找到一个点上方最低的边,即可完成点定位. 时间复杂度$O(m\log m)$. 求出对偶图之后,暴力枚举所有必须保护的古迹,建图求最小割即可. #include<cstdio> #include<cmat

平面图与对偶图

平面图就是能在平面上画出来, 且所有边仅在顶点处相交的图. 对于一个平面图, 我们按照下面方式定义它的对偶图: 将每个平面区域建立一个节点. 对于原图中的每条边, 将与它相邻的两个平面区域对应的节点连边. 点定位: 确定平面中的某个点在哪个区域. 举个例子来说: 对于平面图转化为对偶图, 很多时候图都是方方正正的网格图, 可以方便地进行标号. 但是至于平面图与对偶图的一般转化, 我还不大会, 可以看一下 miskcoo 的博客 . orz GEOTCBRL,  WC 2013 平面图 1A .

BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 433  Solved: 182[Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关:具

【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割

题目描述 在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0).通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图).光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱.当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切).现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2

【BZOJ-2007】海拔 最小割 (平面图转对偶图 + 最短路)

2007: [Noi2010]海拔 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 2095  Solved: 1002[Submit][Status][Discuss] Description YT市是一个规划良好的城市,城市被东西向和南北向的主干道划分为n×n个区域.简单起见,可以将YT市看作一个正方形,每一个区域也可看作一个正方形.从而,YT城市中包括(n+1)×(n+1)个交叉路口和2n×(n+1)条双向道路(简称道路),每条双向道路连接主

[BZOJ 4423] Bytehattan 平面图与对偶图

题意 给定一个 $n \times n$ 的点阵, 形成一个网格图. 最初的时候四连通. $m$ 次操作, 每次删去一条边 $(u, v)$ , 问 $u$ 和 $v$ 是否仍然连通. $2 \le n \le 1500, 1 \le m \le 2n(n - 1)$ . 分析 将平面图转化为它的对偶图. 每次相当于将两个平面区域合并. 对于删去一条边, 若与它相邻的两个区域连通, 那么操作后两个点中有一个点被区域包围, 一个点被隔在了外面, 所以不连通, 反之仍然连通. 实现 1 #inclu

【Luogu】P2766最长不下降子序列问题(暴力网络流)

题目链接 水题qwq,数据都那么水. 我要是出数据的人我就卡$n^3$建图. qwq. 然而这么水的题我!居!然!没!有!1!A!!还!提!交!了!五!遍!!! md从现在开始要锻炼1A率了 看我从今往后做完一道题之后至少检查TM十分钟 可恶qwq. 第一问$n^2$sbDP可解.然而你们知道我提交五遍TM是错在哪里了吗????? 我TM就错在这个pj-,sb到不能再sb的sb暴力DP上!!! 气死我了!!! 关于第二问和第三问,先拆点再拆点qwq. 先把每个点拆成入点和出点用来限制流量,然后把

NOI 2010 海拔 ——平面图转对偶图

[题目分析] 可以知道,所有的海拔是0或1 最小割转最短路,就可以啦 SPFA被卡,只能换DIJ [代码] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; #define maxn 2000005 int h[maxn],to[maxn],ne[maxn],w[ma