1. 程式人生 > >BZOJ 3630 JLOI 2013 鏡面通道 最小點割集

BZOJ 3630 JLOI 2013 鏡面通道 最小點割集

去年省選的題,當時還不會,於是就機智的採用了O(1)演算法(輸出0),得了10分。

現在想想當時還是太菜了啊……

現在也很菜啊,邊連錯了好幾遍。。。

寫這個題還學會了 :: 的用法。。還是太菜了啊。。

廢話不多說,題意簡單。拆點進行最小割即可

注意連線的邊啊,要是考試的時候想出演算法然後錯在這裡可就可惜了

#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 1100
#define MAXE 150010
#define INF 1000000
#define S 0
#define T ((staff + 1) << 1)
using namespace std;

struct Point{
	int x,y;
	Point(int a,int b):x(a),y(b) {}
	Point() {}
}a,b,c,d,temp;
struct Circle{
	Point center;
	int r;
	bool Cross(Point st,Point ed);
}circle[MAX];
struct Square{
	Point down,up;
 	bool Cross(Point st,Point ed) {
		if(InSquare(st) || InSquare(ed))	return true;
		if(st.x == ed.x) {
			if(st.x <= up.x && st.x >= down.x)
				if(st.y <= down.y && st.y >= up.y)
					return true;
		}
		else {
			if(st.y <= up.y && st.y >= down.y)
				if(st.x <= down.x && ed.x >= up.x)
					return true;
		}
		return false;
	}
	bool InSquare(Point a) {
		if(a.x <= up.x && a.x >= down.x && a.y <= up.y && a.y >= down.y)
			return true;
		return false;
	}
}square[MAX];

int staff,points;
int circles,squares;
int head[MAX],total = 1;
int next[MAXE],aim[MAXE],flow[MAXE];
int deep[MAX];

inline double Calc(Point a,Point b);
inline void Add(int x,int y,int f);
bool BFS();
int Dinic(int x,int f);
Point MakePoint(int x,int y);

int main()
{
	cin >> c.x >> c.y >> staff;
	b.x = b.y = 0;
	a.x = 0,a.y = c.y;
	d.y = 0,d.x = c.x;
	for(int flag,i = 1;i <= staff; ++i) {
		scanf("%d",&flag);
		if(flag == 1) {
			scanf("%d%d",&temp.x,&temp.y);
			circle[++circles].center = temp;
			scanf("%d",&circle[circles].r);
		}
		else {
			scanf("%d%d",&temp.x,&temp.y);
			square[++squares].down = temp;
			scanf("%d%d",&temp.x,&temp.y);
			square[squares].up = temp;
		}
	}
	for(int i = 1;i <= circles; ++i) {
		Add(i << 1,i << 1|1,1);
		if(circle[i].Cross(a,c))
			Add(S,i << 1,INF);
		if(circle[i].Cross(b,d))
			Add(i << 1|1,T,INF);
	}
	for(int i = 1;i <= squares; ++i) {
		Add((i + circles) << 1,(i + circles) << 1|1,1);
		if(square[i].Cross(a,c))
			Add(S,(i + circles) << 1,INF);
		if(square[i].Cross(b,d))
			Add((i + circles) << 1|1,T,INF);
	}
	for(int i = 1;i <= circles; ++i)
		for(int j = i + 1;j <= circles; ++j)
			if((Calc(circle[i].center,circle[j].center) <= circle[i].r + circle[j].r))
				Add(i << 1|1,j << 1,INF),Add(j << 1|1,i << 1,INF);
	for(int i = 1;i <= squares; ++i)
		for(int j = i + 1;j <= squares; ++j) {
			bool flag = true;
			Point st = square[j].down,ed = square[j].up;
			if(square[i].Cross(st,MakePoint(ed.x,st.y)))	flag = false;
			if(square[i].Cross(st,MakePoint(st.x,ed.y)))	flag = false;
			if(square[i].Cross(MakePoint(st.x,ed.y),ed))	flag = false;
			if(square[i].Cross(MakePoint(ed.x,st.y),ed))	flag = false;
			if(!flag) {
				Add((i + circles) << 1|1,(j + circles) << 1,INF);
				Add((j + circles) << 1|1,(i + circles) << 1,INF);
			}
		}
	for(int i = 1;i <= circles; ++i)
		for(int j = 1;j <= squares; ++j) {
			bool flag = true;
			Point st = square[j].down,ed = square[j].up;
			if(circle[i].Cross(st,MakePoint(ed.x,st.y)))	flag = false;
			if(circle[i].Cross(st,MakePoint(st.x,ed.y)))	flag = false;
			if(circle[i].Cross(MakePoint(st.x,ed.y),ed))	flag = false;
			if(circle[i].Cross(MakePoint(ed.x,st.y),ed))	flag = false;	
			if(!flag) {
				Add(i << 1|1,(j + circles) << 1,INF);
				Add((j + circles) << 1|1,i << 1,INF);
			}		
		}
	int max_flow = 0,temp;
	while(BFS())
		while(temp = Dinic(S,INF),temp)
			max_flow += temp;
	cout << max_flow;
	return 0;
}

inline double Calc(Point a,Point b)
{
	return sqrt((double)(a.x - b.x) * (a.x - b.x) + 
				(double)(a.y - b.y) * (a.y - b.y));
}

inline void Add(int x,int y,int f)
{
	next[++total] = head[x];
	aim[total] = y;
	flow[total] = f;
	head[x] = total;
	next[++total] = head[y];
	aim[total] = x;
	flow[total] = 0;
	head[y] = total;
}

bool BFS()
{
	static queue<int> q;
	while(!q.empty())	q.pop();
	memset(deep,0,sizeof(deep));
	deep[S] = 1;
	q.push(S);
	while(!q.empty()) {
		int x = q.front(); q.pop();
		for(int i = head[x];i;i = next[i])
			if(flow[i] && !deep[aim[i]]) {
				deep[aim[i]] = deep[x] + 1;
				q.push(aim[i]);
				if(aim[i] == T)	return true;	
			}
	}
	return false;
}

int Dinic(int x,int f)
{
	if(x == T)	return f;
	int temp = f;
	for(int i = head[x];i;i = next[i]) 
		if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) {
			int away = Dinic(aim[i],min(flow[i],temp));
			if(!away)	deep[aim[i]] = 0;
			flow[i] -= away;
			flow[i^1] += away;
			temp -= away;
		}
	return f - temp;
}

bool Circle :: Cross(Point st,Point ed) 
{
	if(st.x == ed.x) {
		if(center.y <= ed.y && center.y >= st.y)
			return abs(center.x - st.x) <= r; 
		return (Calc(center,st) <= r || Calc(center,ed) <= r);
	}
	else {
		if(center.x <= ed.x && center.x >= st.x)
			return abs(center.y - st.y) <= r; 
		return (Calc(center,st) <= r || Calc(center,ed) <= r);
	}
}

Point MakePoint(int x,int y)
{
	Point a(x,y);
	return a;
}

5000+的程式碼啊。。是不是寫麻煩了啊。。