BZOJ1924: [Sdoi2010]所驼门王的宝藏

Description

Input

第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“自由门”。 保证 1≤xi≤R,1≤yi≤C,所有的传送门位置互不相同。

Output

只有一个正整数,表示你确定的路线所经过不同藏宝宫室的最大数目。

Sample Input

10 7 7
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1

Sample Output

9

HINT

测试点编号 N R C 1 16 20 20 2 300 1,000 1,000 3 500 100,000 100,000 4 2,500 5,000 5,000 5 50,000 5,000 5,000 6 50,000 1,000,000 1,000,000 7 80,000 1,000,000 1,000,000 8 100,000 1,000,000 1,000,000 9 100,000 1,000,000 1,000,000 10 100,000 1,000,000 1,000,000

Source

这题做法挺多的吧
首先行和列的处理方法就有很多种
第一种 开虚点 第二种 找到一个行(列)门, 它跟行(列)门连双向边,其他连单向边
至于九宫格的门 直接开map乱连边就好了
然后缩环 然后dp求最长链 非常朴素的思路

我的代码略长 3K 不过1A了2333

http://blog.csdn.net/wxh010910/article/details/53946056

#include <bits/stdc++.h>

using namespace std;

const int maxn = 100010;
const int maxm = 1000010;

inline int read()
{
	int tmp = 0;
	char ch = getchar();
	while( ch < '0' || ch > '9' ) ch = getchar();
	while( ch >= '0' && ch <= '9' ) tmp = tmp * 10 + ch - '0', ch = getchar();
	return tmp;
}

int n, r, c, head[maxn], Head[maxn], cnt, Cnt, ans;

int x[maxn], y[maxn], type[maxn], dfn[maxn], low[maxn], tim, st[maxn], top;

int scc[maxn], num, dp[maxn], size[maxn], q[maxn], ql, qr, d[maxn];

int dx[ 9 ] = { 0, 1, 1, 1, 0, 0, -1, -1, -1 };
int dy[ 9 ] = { 0, 1, 0, -1, 1, -1, 1, 0, -1 };

map < int, int > mp[maxm];
map < pair< int, int >, bool > M;

vector < int > X[maxm], Y[maxm];

struct edge { int to, nxt; } e[ maxm ], E[ maxm ];

inline void addedge(int x, int y) { if( x ^ y ) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; } }
inline void Addedge(int x, int y) { if( x ^ y ) { E[ ++Cnt ].to = y; E[ Cnt ].nxt = Head[ x ]; Head[ x ] = Cnt; d[ y ]++; } }

void dfs(int x)
{
	int tmp = 0;
	dfn[ x ] = low[ x ] = ++tim;
	st[ ++top ] = x;
	for( int i = head[ x ] ; i ; i = e[ i ].nxt )
	{
		int y = e[ i ].to;
		if( !dfn[ y ] ) dfs( y ), low[ x ] = min( low[ x ], low[ y ] );
		else if( !scc[ y ] ) low[ x ] = min( low[ x ], dfn[ y ] );
	}
	if( low[ x ] == dfn[ x ] )
	{
		num++;
		while( tmp ^ x )
		{
			tmp = st[ top-- ];
			scc[ tmp ] = num;
			size[ num ]++;
		}
	}
}

inline void rebuild()
{
	for( int x = 1 ; x <= n ; x++ )
		for( int i = head[ x ] ; i ; i = e[ i ].nxt )
		{
			int y = scc[ x ], z = scc[ e[ i ].to ];
			if( ( y ^ z ) && !M[ make_pair( y, z ) ] )
				Addedge( y, z ), M[ make_pair( y, z ) ] = true;
		}
}

inline void topu()
{
	for( int i = 1 ; i <= num ; i++ )
		dp[ i ] = size[ i ];
	for( int i = 1 ; i <= num ; i++ )
		if( !d[ i ] ) q[ ++qr ] = i;
	while( ql ^ qr )
	{
		int x = q[ ++ql ];
		ans = max( ans, dp[ x ] );
		for( int i = Head[ x ] ; i ; i = E[ i ].nxt )
		{
			int y = E[ i ].to;
			dp[ y ] = max( dp[ y ], dp[ x ] + size[ y ] );
			if( !--d[ y ] ) q[ ++qr ] = y;
		}
	}
}

int main()
{
	n = read(), r = read(), c = read();
	for( int i = 1 ; i <= n ; i++ )
	{
		x[ i ] = read(), y[ i ] = read(), type[ i ] = read();
		X[ x[ i ] ].push_back( i );
		Y[ y[ i ] ].push_back( i );
		mp[ x[ i ] ][ y[ i ] ] = i;
	}
	for( int i = 1 ; i <= r ; i++ )
	{
		int tmp = 0, size = X[ i ].size();
		for( int j = 0 ; j < size ; j++ )
			if( type[ X[ i ][ j ] ] == 1 ) { tmp = X[ i ][ j ]; break; }
		if( tmp )
			for( int j = 0 ; j < size ; j++ )
			{
				addedge( tmp, X[ i ][ j ] );
				if( type[ X[ i ][ j ] ] == 1 ) addedge( X[ i ][ j ], tmp );
			}
	}
	for( int i = 1 ; i <= c ; i++ )
	{
		int tmp = 0, size = Y[ i ].size();
		for( int j = 0 ; j < size ; j++ )
			if( type[ Y[ i ][ j ] ] == 2 ) { tmp = Y[ i ][ j ]; break; }
		if( tmp )
			for( int j = 0 ; j < size ; j++ )
			{
				addedge( tmp, Y[ i ][ j ] );
				if( type[ Y[ i ][ j ] ] == 2 ) addedge( Y[ i ][ j ], tmp );
			}
	}
	for( int i = 1 ; i <= n ; i++ )
		if( type[ i ] == 3 )
			for( int j = 1 ; j <= 8 ; j++ )
				if( mp[ x[ i ] + dx[ j ] ][ y[ i ] + dy[ j ] ] )
					addedge( i, mp[ x[ i ] + dx[ j ] ][ y[ i ] + dy[ j ] ] );
	for( int i = 1 ; i <= n ; i++ )
		if( !dfn[ i ] ) dfs( i );
	rebuild();
	topu();
	return printf( "%d\n", ans ), 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值