直接模拟, 刚开始把题意理解错了,以为每次只有一只蚂蚁走,其实正确的是蚂蚁一哄而上,然后按照题意,各只蚂蚁分别在该停的位置停下。
先转一个吧: http://www.byvoid.com/blog/poi-2001-mro/
做出这道题关键在于读懂题目,尤其是第3条和第4条规则。可以知道,所有蚂蚁是一拥而上的,而且蚂蚁很聪明,它们知道如果在某时一只蚂蚁到瓢虫的路 径与另一只蚂蚁的路径相互包含,就让距离近的蚂蚁继续行进,另一只蚂蚁停留不动。蚂蚁们还会互相礼让,如果要同时进入一个节点,就让编号小的蚂蚁进入,其 它蚂蚁停止不再动。
瓢虫会停留在多个位置,但是都是互相不关联的,我们可以把瓢虫停留的每个位置看作独立的测试点,每个测试点要用到上个测试点的结果,所以我们可以分割考虑每次瓢虫停留。
对于每次瓢虫停留,如果简单地模拟,会很容易超时。我们要把每只蚂蚁一次移动到位。首先从瓢虫的位置开始一遍BFS,找到所有可行进的蚂 蚁,记录每只蚂蚁到瓢虫位置的路径。然后按照路径长度从小到大为第一关键字,蚂蚁编号从小到大为第二关键字把蚂蚁进行排序,排名第一的蚂蚁一定是可以驱逐 瓢虫的蚂蚁,把它的路径上的顶点分别标记时间。然后依次处理每只蚂蚁,如果某只蚂蚁路径上有节点已经被标记时间,则这只蚂蚁的最大移动时间就是已经标记的 时间。在移动时也标记时间,用于影响后面的蚂蚁。这样,移动所有蚂蚁的时间复杂度是O(N+K)的。
算法的总的时间复杂度为O((N+K*logK)*L),可以很快解决问题。实际编写时有很多细节需要注意。
/*
* Problem: POI2001 mro
* Author: Guo Jiabao
* Time: 2009.2.2 21:43
* State: Solved
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN=5001,MAXK=1001,INF=0x7FFFFFFF;
struct edge{int t;edge *next;};
struct adjl{edge *f,*l;};
struct vertex{int id,ant,label;};
struct ant{int vtx,id,dist,hits;};
struct path{path *from;int p;};
edge E[MAXN*2];
adjl A[MAXN];
vertex V[MAXN];
ant Ant[MAXK];
int PL[MAXK],Pt[MAXK][MAXN];
int N,K,L,Ec=-1,Target;
int Order[MAXK];
inline void addedge(int a,int b)
{
if (A[a].f)
A[a].l=A[a].l->next=&E[++Ec];
else
A[a].f=A[a].l=&E[++Ec];
E[Ec].t=b;
}
void init()
{
int i,a,b;
freopen("mro.in","r",stdin);
freopen("mro.out","w",stdout);
scanf("%d",&N);
for (i=1;i<N;i++)
{
scanf("%d%d",&a,&b);
addedge(a,b);
addedge(b,a);
}
for (i=1;i<=N;i++)
V[i].id=i;
scanf("%d",&K);
for (i=1;i<=K;i++)
{
scanf("%d",&a);
V[a].ant=i;
Ant[i].id=i;
Ant[i].vtx=a;
Order[i]=i;
}
scanf("%d",&L);
}
void BFS()
{
path Queue[MAXN],u,v;
int Head=0,Tail=0;
bool vis[MAXN];
int *P;
memset(vis,0,sizeof(vis));
Queue[0].p=Target;
Queue[0].from=0;
vis[Target]=true;
while (Head<=Tail)
{
v.from=&Queue[Head];
u=Queue[Head++];
for (edge *k=A[u.p].f;k;k=k->next)
{
v.p=k->t;
if (!vis[v.p])
{
vis[v.p]=true;
if (V[v.p].ant!=0)
{
int a=V[v.p].ant;
path *b=&v;
PL[a]=0;
P=Pt[a];
while (b->from)
{
P[++PL[a]]=b->p;
b=b->from;
}
P[++PL[a]]=Target;
Ant[a].dist=PL[a]-1;
}
else
Queue[++Tail]=v;
}
}
}
}
void Move()
{
int p,i,j,u,v,MaxStep,Step;
i=Order[1];
Ant[i].hits++;
MaxStep=PL[i];
for (p=1;p<=K && Ant[i=Order[p]].dist<INF;p++)
{
Step=MaxStep;
for (j=1;j<=PL[i];j++)
{
u=Pt[i][j];
if (V[u].label)
{
Step=V[u].label+1;
break;
}
}
u=Pt[i][1];
V[u].ant=0;
for (j=2;j<=Step;j++)
{
v=Pt[i][j];
if (V[u].label+1 > V[v].label)
V[v].label=V[u].label+1;
else
break;
u=v;
}
Ant[i].vtx=u;
V[u].ant=i;
}
}
inline int cmp(const void *a,const void *b)
{
int A=*(int *)a,B=*(int *)b;
if ( Ant[A].dist < Ant[B].dist ) return -1;
if ( Ant[A].dist > Ant[B].dist ) return 1;
if ( Ant[A].id < Ant[B].id ) return -1;
return 1;
}
void clear()
{
int i;
for (i=1;i<=K;i++)
Ant[i].dist=INF;
for (i=1;i<=N;i++)
V[i].label=0;
}
void solve()
{
int i,a;
for (i=1;i<=L;i++)
{
scanf("%d",&Target);
if (V[Target].ant!=0)
{
a=V[Target].ant;
Ant[a].hits++;
}
else
{
clear();
BFS();
qsort(Order+1,K,sizeof(Order[0]),cmp);
Move();
}
}
for (i=1;i<=K;i++)
{
printf("%d %dn",Ant[i].vtx,Ant[i].hits);
}
}
int main()
{
init();
solve();
return 0;
}
------------------------------------------------------------------------------------------------------------------------
下面是自己写的错误理解的代码,也贴上来吧:
/*
* Ants and the ladybug .cpp
*
* Created on: 2011-10-6
*
*/
#include <cstdio>
#include <cstring>
using namespace std;
const int maxN = 5000 + 5;
const int maxK = 1000 + 5;
const int maxL = 500 + 5;
int n, k, l, antPos[maxK], chaseTime[maxK] = {};
int queue[maxN], head, tail;
bool vis[maxN] = {};
struct SList{
int to;
SList *next;
SList(): next(NULL) {}
};
struct STree{
int antNum;
SList list;
STree(): antNum(-1) {}
};
STree tree[maxN];
void cal(int bugPos){
//bug所在位置就有蚂蚁
if(tree[bugPos].antNum != -1){
antPos[tree[bugPos].antNum] = bugPos;
chaseTime[tree[bugPos].antNum]++;
return;
}
SList *tmpList = &tree[bugPos].list;
bool flag = 0;
int minNum = maxK, cur;
head = tail = 0;
vis[bugPos] = 1;
while(tmpList->next != NULL){
if(tree[tmpList->next->to].antNum != -1){
flag = 1;
//记录相同距离的编号最小的蚂蚁。。
if(minNum > tree[tmpList->next->to].antNum)
minNum = tree[tmpList->next->to].antNum;
}
queue[tail++] = tmpList->next->to;
vis[tmpList->next->to] = 1;
tmpList = tmpList->next;
}
//距离为1的节点有蚂蚁
if(flag){
tree[antPos[minNum]].antNum = -1;
antPos[minNum] = bugPos;
tree[bugPos].antNum = minNum;
chaseTime[minNum]++;
return;
}
//插桩,即记录BFS每一层结束的位置,以确定蚂蚁到bug的距离。。
queue[tail++] = -1;
while(head != tail){
cur = queue[head++];
//遇到桩了,说明一层以结束,检查这一层是否有蚂蚁(即离bug最近的蚂蚁),如果没有,继续下一层搜索
if(cur == -1){
queue[tail++] = -1;
if(flag){ //有蚂蚁
tree[antPos[minNum]].antNum = -1;
antPos[minNum] = bugPos;
tree[bugPos].antNum = minNum;
chaseTime[minNum]++;
return;
}
continue;
}
tmpList = &tree[cur].list;
while(tmpList->next != NULL){
//已经访问过
if(vis[tmpList->next->to]){
tmpList = tmpList->next;
continue;
}
//有蚂蚁
if(tree[tmpList->next->to].antNum != -1){
flag = 1;
if(minNum > tree[tmpList->next->to].antNum)
minNum = tree[tmpList->next->to].antNum;
}
queue[tail++] = tmpList->next->to;
vis[tmpList->next->to] = 1;
tmpList = tmpList->next;
}
}
}
int main(){
//输入n
scanf("%d", &n);
int a, b;
SList *tmpNode;
for(int i=0; i<n-1; i++){
scanf("%d %d", &a, &b);
tmpNode = &tree[a].list;
while(tmpNode->next != NULL)
tmpNode = tmpNode->next;
tmpNode->next = new SList;
tmpNode = tmpNode->next;
tmpNode->to = b;
tmpNode->next = NULL;
tmpNode = &tree[b].list;
while(tmpNode->next != NULL)
tmpNode = tmpNode->next;
tmpNode->next = new SList;
tmpNode = tmpNode->next;
tmpNode->to = a;
tmpNode->next = NULL;
}
//输入K
scanf("%d", &k);
int tmpPos;
for(int i=0; i<k; i++){
scanf("%d", &tmpPos);
antPos[i] = tmpPos;
tree[tmpPos].antNum = i;
}
//输入L
scanf("%d", &l);
for(int i=0; i<l; i++){
memset(vis, 0, sizeof(vis));
scanf("%d", &tmpPos);
cal(tmpPos);
}
//输出
for(int i=0; i<k; i++){
printf("%d %d\n", antPos[i], chaseTime[i]);
}
return 0;
}