codeforces 223E 计算几何 图论 网络流思想

25 篇文章 0 订阅
25 篇文章 0 订阅

http://codeforces.com/problemset/problem/223/E

题意: 给你一堆坐标点,然后告诉你他们之间的连接情况,所有的边都是双向的,并且图是连通的。边数,点数都是10w级别

然后开始询问,每个询问是输入图中某个多边形的所有顶点,然后问你这个多边形内部一共有几个点(包括边界上的点)

题解在这里http://codeforces.com/blog/entry/5301

看完后就懂了,关键就是利用流的思想,当选定某个简单多边形的时候,内部的点数就等于流进去的流量和减去流出来的流量和,反正就是流量差,怎么定义很自由

统计的时候不能暴力

利用坐标的极角序处理出一个前缀和就可以很快得到答案

具体见代码

关于多边形的内部究竟在哪一侧还是搞了我很长时间,太纠结了

#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
#define MP make_pair
#define PB push_back 
const int maxn  =  100010;
const double inf = 1e10;
struct Point {
	double x,y;
	Point(){};
	Point(double sx,double sy) : x(sx),y(sy){}
}p[maxn];
double operator / (const Point &b,const Point &a) {
	return atan2(b.y-a.y,b.x-a.x);
}
bool operator  <  (const Point &a,const Point &b){
	if(a.x!=b.x) 
		return a.x<b.x;
	return a.y<b.y;
}
inline double cross(double x1,double y1,double x2,double y2){
	return x1*y2-x2*y1;
}
inline double chacha(Point s,Point a,Point b){
    return cross(a.x-s.x,a.y-s.y,b.x-s.x,b.y-s.y);
}
struct Edge{
	double ang;
	int to;
	Edge(){}
	Edge(double a,int t):ang(a),to(t){};
	bool operator < (const Edge &cmp) const{
		return ang<cmp.ang;
	}
};
vector<Edge> edge[maxn];

map<pair<int,int>,int> sum,flow;

int all[maxn];

int n,m;

inline void add_edge(int u,int v)
{
	Edge k;
    k.to=v;k.ang=p[v]/p[u];
	edge[u].PB(k);
	flow[MP(u,v)]=0;
}
bool vis[maxn];
int dfs(int u,int f)
{
    vis[u]=true;
	int cnt=1;
	for(vector<Edge>::iterator it=edge[u].begin();it!=edge[u].end();it++)
	{
		int v=it->to;
		if(!vis[v])	cnt+=dfs(v,u);
	}
	if(f)
	{
		flow[MP(f,u)]+=cnt;
		flow[MP(u,f)]-=cnt;
	}
	return cnt;
}

int ss[maxn],tt[maxn];

vector<int> cut;
inline int gao(int a,int b,int c)
{
	double bb = p[b]/p[a],cc = p[c]/p[a];
	if(bb < cc) 
	{
		return sum[MP(a,c)] - sum[MP(a,b)] - flow[MP(a,c)];
	}
	else 
	{
		return all[a] + sum[MP(a,c)] - sum[MP(a,b)] - flow[MP(a,c)];
	}
}
void solve()
{
	int ans=0,num=cut.size(),i;
	double s=0;p[0]=Point(0,0);	
	for(i=0;i<num;i++)
		s+=chacha(p[0],p[cut[i==0 ? num-1 : i-1]],p[cut[i]]);
	if(s>0) reverse(cut.begin(),cut.end());//变成顺时针
	for(i=0;i<num;i++)
	{
	     int tmp=gao( cut[i], cut[(i==0 ? num-1 : i-1)] , cut[(i+1)%num] ) ;
         ans+=tmp;
	}
	printf("%d\n",ans+num);
}
int main()
{
	int u,v,q,k,i,j,leftmost,T,cir,c;
	scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++)  scanf("%d%d",&ss[i],&tt[i]);
	for(i=1;i<=n;i++)  scanf("%lf%lf",&p[i].x,&p[i].y);
	for(i=1;i<=m;i++)
	{
		add_edge(ss[i],tt[i]);
		add_edge(tt[i],ss[i]);
	}
	p[T=n+1]=Point(-inf,0);
	for(leftmost=i=1;i<=n;i++) 
		if(p[i]<p[leftmost])   leftmost=i;
	add_edge(T,leftmost);
	add_edge(leftmost,T);
	dfs(T,0);
    for(i=1;i<=n+1;i++) sort(edge[i].begin(),edge[i].end());
	for(i=1;i<=n+1;i++)
	{
		int pre=i;
		sum[MP(i,i)] = 0;
		for(vector<Edge>::iterator it=edge[i].begin();it!=edge[i].end();it++)
		{
			all[i]+=flow[MP(i,it->to)];
			sum[MP(i,it->to)] = sum[MP(i,pre)] + flow[MP(i,it->to)];
			pre=it->to;
		}
	}
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d",&k);cut.clear();
		for(i=1;i<=k;i++) scanf("%d",&c),cut.PB(c);
		solve();
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值