hdu 4183 Pahom on Water 最大流

一个平面上有n个圆, 每个圆都有一个频率, 有两个频率为400和789的圆, 问是否能从频率为400的圆走到频率为789的圆, 并从频率为789的圆走回频率为400的圆, 并且除了频率为400的圆, 其他圆只能走一次。 如果两个圆相交,则去的时候能从频率小的圆走到频率大的圆, 回来的时候能从频率大的圆走到频率小的圆。


思路:

假设起点为s, 终点为t, 其实就是问有没有从s到t的两条不相交路径。

用最大流搞, 把每个点拆为2个, 连一条容量为1的边, 表示只能走一次, 然后求出最大流是不是2就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;

#define mxn 800
#define inf 0x3f3f3f3f

struct edge {
	int u, v, cap, flow;
	edge() {}
	edge( int u, int v, int cap, int flow ): u( u ), v( v ), cap( cap ), flow( flow ) {}
};
struct dinic {
	int n, m, s, t, cur[mxn], d[mxn];
	vector<edge> edges;
	vector<int> g[mxn];

	void add( int u, int v, int cap ) {
		edges.push_back( edge( u, v, cap, 0 ) );
		edges.push_back( edge( v, u, 0, 0 ) );
		m = edges.size();
		g[u].push_back( m - 2 );
		g[v].push_back( m - 1 );
	}
	bool bfs() {
		memset( d, -1, sizeof( d ) );
		d[s] = 0;
		queue<int> q;
		q.push( s );
		while( !q.empty() ) {
			int x = q.front();
			q.pop();
			for( int i = 0; i < g[x].size(); ++i ) {
				edge& e = edges[g[x][i]];
				if( d[e.v] == -1 && e.cap > e.flow )
					d[e.v] = d[x] + 1, q.push( e.v );
			}
		}
		return d[t] != -1;
	}

	int dfs( int x, int a ) {
		if( x == t || a == 0 )
			return a;
		int flow = 0, f;
		for( int& i = cur[x]; i < g[x].size(); ++i ) {
			edge& e = edges[g[x][i]];
			if( d[e.v] == d[x] + 1 && ( f = dfs( e.v, min( a, e.cap - e.flow ) ) ) > 0 ) {
				flow += f;
				e.flow += f;
				edges[g[x][i]^1].flow -= f;
				a -= f;
				if( !a )
					break;
			}
		}
		return flow;
	}
	int mf( int s, int t ) {
		this -> s = s, this -> t = t;
		int flow = 0;
		while( bfs() ) {
			memset( cur, 0, sizeof( cur ) );
			flow += dfs( s, inf );
		}
		return flow;
	}

}*solver;

struct node {
	double x, y, hz, r;
	node() {}
	void input() {
		scanf( "%lf%lf%lf%lf", &hz, &x, &y, &r );
	}
}p[mxn];

int n, s, t;
double dis( node a, node b ) {
	return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) );
}
bool check( int i, int j ) {
	if( p[i].hz >= p[j].hz )
		return 0;
	if( dis( p[i], p[j] ) <= p[i].r + p[j].r )
		return 1;
	return 0;
}
int main() {
//	freopen( "tt.txt", "r", stdin );
	int cas;
	solver = NULL;
	scanf( "%d", &cas );
	while( cas-- ) {
		if( solver != NULL )
			delete solver;
		solver = new dinic;
		scanf( "%d", &n );
		for( int i = 0; i < n; ++i ) {
			p[i].input();
			if( fabs( p[i].hz - 400 ) < 1e-8 )
				s = i;
			if( fabs( p[i].hz - 789 ) < 1e-8 )
				t = i;
		}
		for( int i = 0; i < n; ++i ) {
			for( int j = i + 1; j < n; ++j ) {
				if( check( i, j ) )
					solver -> add( ( i << 1 ) | 1, j << 1, 1 );
				if( check( j, i ) )
					solver -> add( ( j << 1 ) | 1, i << 1, 1 );
			}
			solver -> add( i << 1, ( i << 1 ) | 1, 1 );
		}
		solver -> add( s << 1, s << 1 | 1, 1 );
		solver -> add( t << 1, t << 1 | 1, 1 );
		solver -> add( 775, s << 1, 2 );
		solver -> add( ( t << 1 ) | 1, 776, 2 );
		int ans = solver -> mf( 775, 776 );
		if( ans == 2 ) 
			puts( "Game is VALID" );
		else
			puts( "Game is NOT VALID" );
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值