Knight Match Play | ||||||
| ||||||
Description | ||||||
There are two knight teams, they have N and M knights respectively. The knights are numbered from 1 to N and 1 to M in their own team. They are trapped in a W*H grid puzzle. The puzzle only has four exituses which are the four corners of the puzzle. Only the directions up,down,left,right could the knight move to and the time move from one grid to the adjacent is fixed. They can form a "fight partner" if two knights sufficing the following conditions: 1, The two knights come from different teams. 2, Both of them can arrive to one of the exituses. 3, The least time need to arrive to one of the exituses is same. So how many "fight partners" they can form? For this action, the leader gives the follow directives: | ||||||
Input | ||||||
There are several test cases. The input of every test case are described as below. First line, there are four integers N,M,W,H. (0<n,m<300, 10<w,h<50). Then there are H lines, each line with W characters indicate for the puzzle. A character of '.' indicate the grid is empty, every empty grid could contain infinitely of knights. A character of '#' means the grid has a barrier and none knight can step into it. The four corners are empty. Then there N+M lines, each line with a pair of integers (x,y)(0<=x<h,0<=y<w) originally. The input will finish with the end of file | ||||||
Output | ||||||
An integer indicate for the maximal number of "fight partner" they can form. | ||||||
Sample Input | ||||||
4 3 7 6 | ||||||
Sample Output | ||||||
3
| ||||||
Source | ||||||
Hunan University 2011 the 7th Programming Contest | ||||||
Recommend | ||||||
万祥 |
题目大意:
给你一个H*W大小的一个迷宫,其中#表示不能走,“.”表示可以走,
现在迷宫的出口在四个角落(左上.左下.右上.右下);
我们规定一共有两活人,一伙N个,一伙M个,初始的时候编号按照输入顺序编号.
现在规定合作伙伴:
①合作伙伴是两个人,并且来自不同的阵营。
②两个人到达其最近的出口耗时相同。
然后我们需要将两个阵营的骑士重新编号。
重新编号的规则按照:按照逃出迷宫从小到大的时间排序,然后按照这个顺序从新编号。对于时间相同的,按照原序列优先级编号。
然后得到两个重新编号的数组A.B.让你在任意一个数组中取任意一段连续子序列,让其是另外一个数组的子串,求这个合法子段的最长长度。
思路:
1、根据手动测试数据范围已知,n,m不大于300.W.H不大于500.
2、题目很复杂,我们首先简化问题,其实就是让你①先求出每个人逃出迷宫的时间,然后按照时间点从小到大排序得到两个数组,②然后求一个数组任意取一段连续子段是另外一个数组的子串即可,我们需要求一个最大长度。
3、那么我们首先处理前部分任务:
我们对于一个图的遍历的时间复杂度是O(nm)如果我们对于每一个骑士进行Bfs,肯定是超时的,那么我们Bfs四个起点,维护一个数组step【i】【j】.表示从任意起点到(i,j)这个位子的最短时间消耗,反过去考虑,step【i】【j】其实就是从(i,j)这一点,到任意出口的最小时间花费。
那么对于每个骑士来讲,其逃出的时间,就是step【x】【y】;
这部分时间复杂度:O(nm);
4、然后我们处理后置任务。
①对于我们处理出来的两个数组,按照时间从小到大先排个序,模拟题目要求。
②考虑到KMP匹配的特性,我们只需O(n)枚举A.B数组中较小的那个序列的起点,去匹配另一个序列即可,过程维护一个最大匹配长度值。
③这里有一个trick.输入数据不保证一个点一定能够走到出口。所以从小到大排序结束之后,要重新界定一下数组的大小(就是要把不能走到终点的那些去除掉)。
④过程维护一个最大值即可。
时间复杂度O(min(lena,lenb)*(lena+lenb));
5、总体来说题目比较综合,而且坑点十足,尼玛对拍数据都调了很久才过,给这个题一个好评吧,估计也没几个人能做这个题了(- -);
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
int x,y;
}now,nex;
char mp[505][505];
int step[505][505];
int numa[505];
int numb[505];
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int a[500];
int b[500];
int naxt[2500];
int conta,contb,n,m;
int lena,lenb;
int Bfs()
{
queue<node >s;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
step[i][j]=0x3f3f3f3f;
if((i==0&&j==0)||(i==n-1&&j==m-1)||(i==n-1&&j==0)||(i==0&&j==m-1))
{
now.x=i;
now.y=j;
step[i][j]=0;
s.push(now);
}
}
}
while(!s.empty())
{
now=s.front();
s.pop();
for(int i=0;i<4;i++)
{
nex.x=now.x+fx[i];
nex.y=now.y+fy[i];
if(nex.x>=0&&nex.x<n&&nex.y>=0&&nex.y<m&&mp[nex.x][nex.y]!='#')
{
if(step[nex.x][nex.y]>step[now.x][now.y]+1)
{
step[nex.x][nex.y]=step[now.x][now.y]+1;
s.push(nex);
}
}
}
}
return 0;
}
void set_naxt()//子串的naxt数组
{
int i=0,j=-1;
naxt[0]=-1;
while(i<lenb)
{
if(j==-1||b[i]==b[j])
{
i++; j++;
naxt[i]=j;
}
else
j=naxt[j];
}
}
int KMP()
{
int maxnlen=0;
int i=0,j=0;
set_naxt();
while(i<lena)
{
if(j==-1||a[i]==b[j])
{
i++;j++;
maxnlen=max(j,maxnlen);
}
else
{
maxnlen=max(j,maxnlen);
j=naxt[j];
}
if(j==lenb)
{
return lenb;
}
}
return maxnlen;
}
int main()
{
while(~scanf("%d%d%d%d",&conta,&contb,&m,&n))
{
for(int i=0;i<n;i++)scanf("%s",mp[i]);
Bfs();
for(int i=0;i<conta;i++)
{
int x,y;
scanf("%d%d",&x,&y);
numa[i]=step[x][y];
}
for(int i=0;i<contb;i++)
{
int x,y;
scanf("%d%d",&x,&y);
numb[i]=step[x][y];
}
sort(numa,numa+conta);
sort(numb,numb+contb);
for(int i=0;i<conta;i++)
{
if(numa[i]==0x3f3f3f3f)
{
conta=i;
break;
}
}
for(int i=0;i<contb;i++)
{
if(numb[i]==0x3f3f3f3f)
{
contb=i;
break;
}
}
int output=0;
if(conta<contb)
{
lena=contb;
for(int i=0;i<contb;i++)
{
a[i]=numb[i];
}
for(int i=0;i<conta;i++)
{
lenb=0;
for(int j=i;j<conta;j++)
{
b[lenb++]=numa[j];
}
output=max(KMP(),output);
}
}
else
{
lena=conta;
for(int i=0;i<conta;i++)
{
a[i]=numa[i];
}
for(int i=0;i<contb;i++)
{
lenb=0;
for(int j=i;j<contb;j++)
{
b[lenb++]=numb[j];
}
output=max(KMP(),output);
}
}
printf("%d\n",output);
}
}