【题目描述】
消棋子是一个有趣的游戏。游戏在一个r * c的棋盘上进行。棋盘的每个格子,要么是空,要么是一种颜色的棋子。同一种颜色的棋子恰好有两个。每一轮,玩家可以选择一个空格子(x, y),并选择上下左右四个方向中的两个方向,如果在这两个方向上均存在有棋子的格子,而且沿着这两个方向上第一个遇到的棋子颜色相同,那么,我们将这两个棋子拿走,并称之为合法的操作。否则称这个操作不合法,游戏不会处理这个操作。游戏的目的是消除尽量多的棋子。
给出这样一个游戏和一个人的玩法。你需要:
z 指出此人能消去多少棋子。
z 给出一种能消去最多棋子的方案。
【输入格式】
在输入文件eliminate.in中,第一行给出了整数r, c。第二行给出了整数n,表示不同颜色数。接下来n行,第i行含4个整数a[i], b[i], c[i], d[i],表示颜色
为i的两个格子分别是(a[i], b[i]), (c[i], d[i])。然后是一个整数m,表示此人的操作数。接下来m行,每行有2个整数和2个字母,代表了他选择的格子,以及两个方向。我们用“UDLR”分别表示上下左右。
【输出格式】
在输出文件eliminate.out中,第一行输出此人能消去多少棋子。第二行含一个整数k(0 ≤k ≤10^6),表示你给出的方案的操作数。接下来k行,每行2个整数和2个字母,代表你选择的格子以及两个方向。
【样例输入】
4 4
4
1 1 1 4
1 2 3 4
1 3 3 2
4 1 2 3
6
2 3 U R
2 1 D R
2 2 L R
2 4 L D
3 1 L R
3 3 L U
【分析】
其实并不是特别难,也没有传说中的那么烦。
具体思路大概就是开两个Set维护行列相邻的状况,基于STL的二分查找。
第一问直接模拟就行了。
第二问大概也就是模拟= =,先把可以消掉的棋子先消掉,由于这可能影响到所在行所在列的其它棋子,所以我们要维护一个队列,每当有棋子被消掉就把他们加到队列里去。
当时我敲烦起来了,而且机房就要关门了TAT
于是就没有考虑效率直接暴力判断各个方向,具体实现就是在Set里查找当前结点(从队首取出来的)两个方向一共六种的棋子编号是否相同,相同就从Set里删除,入队。
这里是一个小例子和小BUG。
讲比较难讲清楚,这里是代码,比较偷懒直接复制粘贴了所以写的有些长= =
然后就是说还有个比较大的BUG……STL_Set不开-O2要超时……感谢BZOJ!
/**************************************************************
Problem: 3519
User: Array98
Language: C++
Result: Accepted
Time:5784 ms
Memory:35740 kb
****************************************************************/
#include
#include
#include
#include
#define mk(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> Pii;
const int MaxN=100010;
set Line[MaxN],Row[MaxN];
Pii A1[MaxN],B1[MaxN],C1[MaxN],D1[MaxN];
const Pii NUL=mk(0,0);
int R,C,N,Ans=0;
int Delete[MaxN];
queue <int> Q;
struct Node { int X,Y; char D1,D2; } S[100010];
void Init()
{
int a,b,c,d;
scanf("%d%d",&R,&C);
scanf("%d",&N);
for (int i=1; i<=N; i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
A1[i].first=a;B1[i].first=b;C1[i].first=c;D1[i].first=d;
A1[i].second= B1[i].second= C1[i].second= D1[i].second=i;
}
}
void Clear()
{
for (int i=0; i<=R; i++) { Line[i].clear(); Line[i].insert(mk(0,0)); Line[i].insert((mk(MaxN,0)));}
for (int i=0; i<=C; i++) { Row[i].clear(); Row[i].insert(mk(0,0)); Row[i].insert((mk(MaxN,0)));}
for (int i=1; i<=N; i++)
{
Line[A1[i].first].insert(B1[i]);
Line[C1[i].first].insert(D1[i]);
Row[B1[i].first].insert(A1[i]);
Row[D1[i].first].insert(C1[i]);
}
}
void Solve_ZZY()
{
Clear();
int M,X,Y,Ans=0; char D_X,D_Y; Pii Find1,Find2;
set ::iterator It;
scanf("%d",&M);
for (int i=0; iint flag1=0,flag2=0;
scanf("%d %d %c %c\n",&X,&Y,&D_X,&D_Y);
Find1=*Line[X].lower_bound(mk(Y,0));
if (Find1.first==Y) continue;
Find1=Find2=NUL;
if (D_X=='U') { Find1=*(--Row[Y].lower_bound(mk(X,0))); flag1=(Find1.second==0)?0:1;}
if (D_X=='D') { Find1=*(Row[Y].upper_bound(mk(X,MaxN))); flag1=(Find1.second==0)?0:1;}
if (D_X=='L') { Find1=*(--Line[X].lower_bound(mk(Y,0))); flag1=(Find1.second==0)?0:2;}
if (D_X=='R') { Find1=*(Line[X].upper_bound(mk(Y,MaxN))); flag1=(Find1.second==0)?0:2;}
if (D_Y=='U') { Find2=*(--Row[Y].lower_bound(mk(X,0))); flag2=(Find2.second==0)?0:1;}
if (D_Y=='D') { Find2=*(Row[Y].upper_bound(mk(X,MaxN))); flag2=(Find2.second==0)?0:1;}
if (D_Y=='L') { Find2=*(--Line[X].lower_bound(mk(Y,0))); flag2=(Find2.second==0)?0:2;}
if (D_Y=='R') { Find2=*(Line[X].upper_bound(mk(Y,MaxN))); flag2=(Find2.second==0)?0:2;}
if (flag1 && flag2 && Find1.second==Find2.second)
{
Ans+=1;
if (flag1==1) { Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second)); }
if (flag1==2) { Line[X].erase(Find1); Row[Find1.first].erase(mk(X,Find1.second)); }
if (flag2==1) { Row[Y].erase(Find2); Line[Find2.first].erase(mk(Y,Find2.second)); }
if (flag2==2) { Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second)); }
}
}
printf("%d ",Ans);
}
inline void Print(int X, int Y, char D1, char D2) { S[Ans]=(Node){X,Y,D1,D2}; }
inline void Recheck(int X, int Y, int Id)
{
Pii Find1,Find2;
Find1=*Line[X].lower_bound(mk(Y,0));
if (Find1.first==Y) return;
//UD
Find1=*(--Row[Y].lower_bound(mk(X,0)));
Find2=*(Row[Y].upper_bound(mk(X,MaxN)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Delete[Id]=1; Ans++; Q.push(Id); Print(X,Y,'U','D');
Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second));
Row[Y].erase(Find2); Line[Find2.first].erase(mk(Y,Find2.second));
return;
}
//LR
Find1=*(--Line[X].lower_bound(mk(Y,0)));
Find2=*(Line[X].upper_bound(mk(Y,MaxN)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Delete[Id]=1; Ans++; Q.push(Id); Print(X,Y,'L','R');
Line[X].erase(Find1); Row[Find1.first].erase(mk(X,Find1.second));
Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second));
return;
}
//UR
Find1=*(--Row[Y].lower_bound(mk(X,0)));
Find2=*(Line[X].upper_bound(mk(Y,MaxN)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Delete[Id]=1; Ans++; Q.push(Id); Print(X,Y,'U','R');
Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second));
Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second));
return;
}
//UL
Find1=*(--Row[Y].lower_bound(mk(X,0)));
Find2=*(--Line[X].lower_bound(mk(Y,0)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Delete[Id]=1; Ans++; Q.push(Id); Print(X,Y,'U','L');
Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second));
Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second));
return;
}
//DR
Find1=*(Row[Y].upper_bound(mk(X,MaxN)));
Find2=*(Line[X].upper_bound(mk(Y,MaxN)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Q.push(Id); Delete[Id]=1; Ans++; Print(X,Y,'D','R');
Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second));
Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second));
return;
}
//DL
Find1=*(Row[Y].upper_bound(mk(X,MaxN)));
Find2=*(--Line[X].lower_bound(mk(Y,0)));
if (Find1.second && Find1.second==Id && Find1.second==Find2.second && !Delete[Id])
{
Delete[Id]=1; Ans++; Q.push(Id); Print(X,Y,'D','L');
Row[Y].erase(Find1); Line[Find1.first].erase(mk(Y,Find1.second));
Line[X].erase(Find2); Row[Find2.first].erase(mk(X,Find2.second));
return;
}
}
inline void GotoCheck(int Id)
{
int X1=A1[Id].first,Y1=B1[Id].first,X2=C1[Id].first,Y2=D1[Id].first;
if (X1==X2) { Recheck(X1,(Y1+Y2)/2,Id); return; }
if (Y1==Y2) { Recheck((X1+X2)/2,Y1,Id); return; }
Recheck(X1,Y2,Id);
Recheck(X2,Y1,Id);
}
inline void Check(int X, int Y)
{
Pii Find;
Find=*(--Row[Y].lower_bound(mk(X,0))); if (Find.second) GotoCheck(Find.second);
Find=*(Row[Y].upper_bound(mk(X,MaxN))); if (Find.second) GotoCheck(Find.second);
Find=*(--Line[X].lower_bound(mk(Y,0))); if (Find.second) GotoCheck(Find.second);
Find=*(Line[X].upper_bound(mk(Y,MaxN)));if (Find.second) GotoCheck(Find.second);
}
inline void Get_Start()
{
for (int i=1; i<=N; i++)
{
int X1=A1[i].first,Y1=B1[i].first,X2=C1[i].first,Y2=D1[i].first;
if (X1==X2) { Recheck(X1,(Y1+Y2)/2,i); continue; }
if (Y1==Y2) { Recheck((X1+X2)/2,Y1,i); continue; }
Recheck(X1,Y2,i);
Recheck(X2,Y1,i);
}
}
void Solve_YPC()
{
Clear();
Get_Start();
while(!Q.empty())
{
int i=Q.front(); Q.pop();
int X1=A1[i].first,Y1=B1[i].first,X2=C1[i].first,Y2=D1[i].first;
Check(X1,Y1);
Check(X2,Y2);
}
printf("%d\n",Ans);
for (int i=1; i<=Ans; i++) printf("%d %d %c %c\n",S[i].X,S[i].Y,S[i].D1,S[i].D2);
}
int main()
{
Init();
Solve_ZZY();
Solve_YPC();
return 0;
}
谢郭嘉!