zoj 2864 Catch the thief

WA了五版,贡献了50、60次WA。。。我成功地把这个题的AC率降低了好几个百分点。。。伟大吧。。

 

纠结两天多了><。

 

废话不多说了,总之,还是道好题的。

 

说下题意,给你一个图,无向图,有起点,终点,给出q个询问,询问在时间t的时候,小偷可能在哪几个地点。小偷是沿最短路从起点逃到终点的。

 

因为最短路可能有多条,所以造成同一时间,小偷所在地点不同。

 

最短路后,然后找所有的最短路径。以前做过类似的,是从终点往起点找。如果找到点i,dis[i] + edge(i,now) == dis[now],说明这个i点是最短路上的点,然后将它入队,继续找。

 

关于时间的统计,找到一个点的时候,i 点 到 now点的时间,需要统计下,因为可能一个点会用到多次,所以节点的时间不统计,标记下这个节点是最短路里的,最后再统一加上。只要把 dis[i] + 1 到 dis[now] - 1的时间段都加一即可。但是,WA了一天的我想明白了,这个方法不可取。

 

我开始的时候没有想清楚,以为q询问的结果再1000以内,所以还挺高兴得开了short型的1000W的数组。然后WA在3秒多,然后一直想特殊情况。。。直到上午,排除所有的特殊情况,想了下,测试了下,发现,确实存在大于1000的结果,事实上,肯定有大于short型的结果的,所以,很悲剧地WA掉了。

 

网上只有一个程序,是用DFS的,我的想法没有错,所以想办法改进。

 

把所有询问存一下,把在搜索过程询问时间在 dis[i] + 1 到 dis[now] - 1的时间段内的结果++,最后依次输出这些结果即可。

 

这个过程完了之后,需要把在最短路径里的点再算上,看看询问的点是否为这些点,如果是的话,这个询问再++,即可。

 

A掉了,高兴^ ^.

 

#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <algorithm> #define MAX 1010 using namespace std; short map[MAX][MAX]; int dis[MAX]; void SPFA(int from,int to,int n) { queue<int> q; bool inq[MAX]; memset(inq,false,sizeof(inq)); for(int i=0; i<=n; i++) dis[i] = INT_MAX; int now = from; inq[now] = true; dis[now] = 0; q.push(now); while( !q.empty() ) { int now = q.front(); q.pop(); inq[now] = 0; for(int k=1; k<=n; k++) if( map[now][k] && dis[k] > dis[now] + map[now][k] ) { dis[k] = dis[now] + map[now][k]; if( !inq[k] ) { q.push(k); inq[k] = true; } } } } bool b[MAX][MAX]; queue<short> q; bool inq[MAX]; int ans[MAX],lala; int tt[MAX]; int BFS(int from,int to,int n) { bool used[MAX]; memset(inq,0,sizeof(inq)); memset(used,false,sizeof(used)); memset(b,false,sizeof(b)); memset(ans,0,sizeof(ans)); q.push(to); used[to] = used[from] = inq[to] = true; int k; while( !q.empty() ) { int now = q.front(); q.pop(); inq[now] = false; for(int i=1; i<=n; i++) if( !b[i][now] && map[i][now] && dis[i] != INT_MAX && dis[now] == dis[i] + map[i][now] ) { used[i] = true; b[i][now] = b[now][i] = true; for(k=0; k<lala; k++) { if( tt[k] >= dis[i]+1 && tt[k] < dis[now] ) ans[k]++; } if( !inq[i] ) { inq[i] = true; q.push(i); } } } for(int i=1; i<=n; i++) // 如果有在最短路径上的点,就加上去,因为上面没有加这些点 for(int k=0; k<lala; k++) if( used[i] && dis[i] == tt[k] ) ans[k]++; } int main() { int n,m,s,t,from,to,len; int flag = 0; while( ~scanf("%d%d%d%d",&n,&m,&s,&t) ) { if( flag ) printf("/n"); flag = 1; memset(map,0,sizeof(map)); while( m-- ) { scanf("%d%d%d",&from,&to,&len); map[from][to] = map[to][from] = len; } SPFA(s,t,n); scanf("%d",&lala); for(int i=0; i<lala; i++) scanf("%d",&tt[i]); BFS(s,t,n); for(int i=0; i<lala; i++) { if( tt[i] >= dis[t] || tt[i] == 0 ) printf("1/n"); else printf("%d/n",ans[i]); } } return 0; }  

 

你可能感兴趣的:(测试)