time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Let's consider the following game. We have a rectangular field n×m in size. Some squares of the field contain chips.
Each chip has an arrow painted on it. Thus, each chip on the field points in one of the following directions: up, down, left or right.
The player may choose a chip and make a move with it.
The move is the following sequence of actions. The chosen chip is marked as the current one. After that the player checks whether there are more chips in the same row (or in the same column) with the current one that are pointed by the arrow on the current chip. If there is at least one chip then the closest of them is marked as the new current chip and the former current chip is removed from the field. After that the check is repeated. This process can be repeated several times. If a new chip is not found, then the current chip is removed from the field and the player's move ends.
By the end of a move the player receives several points equal to the number of the deleted chips.
By the given initial chip arrangement determine the maximum number of points that a player can receive during one move. Also determine the number of such moves.
Input
The first line contains two integers n and m (1≤n,m,n×m≤5000). Then follow n lines containing m characters each − that is the game field description. "." means that this square is empty. "L", "R", "U", "D" mean that this square contains a chip and an arrow on it says left, right, up or down correspondingly.
It is guaranteed that a field has at least one chip.
Output
Print two numbers − the maximal number of points a player can get after a move and the number of moves that allow receiving this maximum number of points.
Examples
Input
4 4 DRLD U.UL .UUR RDDL
Output
10 1
Input
3 5 .D... RRRLL .U...
Output
6 2
Note
In the first sample the maximum number of points is earned by the chip in the position (3,3). You can see its progress at the following picture:
All other chips earn fewer points.
【分析】
题意:给出一张图,有空白点以及方向UDLR,表示上下左右,到达当前点如果是方向,那么就按照方向继续走向下一格,跳过中间所有的空白格,若当前方向只剩下空白格,那么就结束,问从任意起点出发,能走的最多步数是多少,并且有多少种方案
这种代码首先考虑爆搜,dfs,bfs都可以因为每次搜索一个点只会经过一次,所以复杂度是O(5000),那么起点也是5000个
所以复杂度粗略估计是O(5000*5000),但是交上去会T...
P.S.当然在我们学校OJ是不会T的。。数据放小了...
但是这里显然还有一个复杂度没有计算,虽然理论上是每个点只经过一次,但是在真正搜索的时候,要从(x,y)向某个方向dir搜索下一个方向块的时候,还是会经过中间所有空白点的,所以复杂度还存在一个√500
所以真实的复杂度应该是5000*5000*70,所以才会超时......那么显然这个搜索中5000*5000是必须要存在的复杂度,那么我们优化掉这个70就可以了
那也很简单,这个70的存在只是因为每次从(x,y)向某个方向寻找下一个块的时候会经过空白块,所以我们不再经过空白块就可以了,把找下一块的复杂度优化到1即可,显然这件事情链表就可以解决...那么在一张二维图上我们需要四个方向的链表..也就是十字链表了...当然同时因为这张图是n*m<=5000 ,而不是5000*5000,所以建一张5000*5000的链表显然是没有意义的...hash一下就可以了
【代码】
#include<bits/stdc++.h>
using namespace std;
char s[5010][5010];
int U[5050],D[5050],L[5050],R[5050];
int n,m;
void init(){
for (int i = 0 ; i < n ; ++i){
int l = -1;
for (int j = 0 ; j < m ; ++j)
if (s[i][j] != '.'){
int now = i * m + j;
L[now] = l; //l表示上一个节点的位置,上一个节点就是这个节点的左结点
if (l != -1) R[l] = now; //上一个节点的右节点就是这个节点的右节点
l = now; //记录当前的节点状态。
}
R[l] = -1; //每一行的最后一个节点的右节点是-1
}
//分开处理 上下方向的链表和左右方向的链表
for (int i = 0 ; i < m ; ++i){ //同上
int l = -1;
for (int j = 0 ; j < n ; ++j)
if (s[j][i] != '.'){
int now = j * m + i;
U[now] = l;
if (l != -1) D[l] = now;
l = now;
}
D[l] = -1;
}
}
int dfs(int x,int y){
int now = x * m + y;
//到达当前节点(x,y) 首先处理十字链表,把当前节点删除
if (U[now] != -1) D[U[now]] = D[now]; //如果这个点a上面还存在节点b,那么节点b向下的链表指向应该跳过a,指向a下面的点
if (D[now] != -1) U[D[now]] = U[now]; //如果这个点a下面还存在节点b,那么节点b向上的链表指向应该跳过a,指向a上面的点
if (L[now] != -1) R[L[now]] = R[now]; //如果这个点a左边还存在节点b,那么节点b右边的链表指向应该跳过a,指向a右边的点
if (R[now] != -1) L[R[now]] = L[now]; //如果这个点a右边还存在节点b,那么节点b左边的链表指向应该跳过a,指向a左边的点
//删除当前点(x,y)后,向当前点的方向下一格继续搜索
int go;
if (s[x][y] == 'U') go = U[now];
else if (s[x][y] == 'D') go = D[now];
else if (s[x][y] == 'L') go = L[now];
else if (s[x][y] == 'R') go = R[now];
if (go == -1) return 1;
return dfs(go/m,go%m) + 1;
}
int main()
{
int ans = -1, num = 0;
scanf("%d%d",&n,&m);
for (int i = 0 ; i < n ; ++i) scanf("%s",s[i]);
for (int i = 0 ; i < n ; ++i)
for (int j = 0 ; j < m ; ++j)
if (s[i][j] != '.'){ // 遍历所有方向块,作为起点搜索一遍整张图
init(); // 初始化链表
int now = dfs(i,j);
if (now > ans) ans = now,num = 1;
else if (now == ans) ++num;
}
printf("%d %d\n",ans,num);
return 0;
}
因为数据放水了
所以下面这个简单的dfs爆搜也可以过
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5005;
char s[maxn][maxn];
bool a[maxn][maxn];
int n,m,tmp;
int dx[] = { -1,0,1,0 };
int dy[] = { 0,1,0,-1 };
int bin( char a )
{
if( a=='U' ) return 0;
if( a=='R' ) return 1;
if( a=='D' ) return 2;
return 3;
}
int check( int x,int y )
{
if( x>=n||x<0 ) return 0;
if( y>=m||y<0 ) return 0;
return 1;
}
void dfs( int x, int y ,int up)
{
if( s[x][y]!='.'&&a[x][y]==false )
{
tmp++; a[x][y] = true;
int to = bin( s[x][y] );
int xx = x+dx[to];
int yy = y+dy[to];
if( check( xx,yy ) ) dfs( xx,yy,to );
}
else
{
int xx = x+dx[up];
int yy = y+dy[up];
if( check( xx,yy ) )
dfs( xx,yy,up );
}
}
int main()
{
while( scanf( "%d%d", &n, &m )==2 )
{
for( int i=0;i<n;i++ )
scanf( "%s", s[i] );
int ans = 0, cnt = 0;
for( int i=0;i<n;i++ )
for( int j=0;j<m;j++ )
if( s[i][j]!='.' )
{
memset( a, false, sizeof(a) );
tmp = 0;
dfs( i,j,bin( s[i][j] ) );
if( ans<tmp )
{
ans = tmp; cnt = 1;
}
else if( ans==tmp )
{
cnt++;
}
// printf( "%d %d\n", ans ,cnt );
}
printf( "%d %d\n", ans ,cnt );
}
return 0;
}