RQNOJ190 拦截匪徒 (重庆一中高2018级信息学竞赛测验2) 解题报告

来源:互联网 发布:网络新技术包括哪些 编辑:程序博客网 时间:2024/05/02 06:51
【问题描述】
某城市的地图是一个由N个点组成的无向图,每个点代表一个区。现在p区发生抢劫案,而警察为了截住劫匪须埋伏在一个劫匪必经区域。由于不知道劫匪会向哪个区逃窜,所以市长要求对于任意一个劫匪可能逃向的区j,找出一个可以拦截劫匪的区域k(k!=p,k!=j),即劫匪从p区逃向j区,必须经过k区。由于地区j可能为匪徒的老巢所在,所以警察希望能在路上拦截住土匪,而不是在j区抓获。
 
【输入格式】  
第一行N,p,接下来得为N*N的矩阵A,A[i][j]=1,表示i与j右路相连,A[i][j]=0则没有。


【输出格式】  
输出N-1行,输出警察应在哪个些置埋伏,按j=1、2、…p-1、p+1、…N的顺序输出,若有多点,由小到大顺序输出。如果没有合适的埋伏位置,或者在p与j根本就不连通,则输出No。




【输入输出样例1】
catch.in

5 1

0 1 1 0 0

1 0 1 1 0

1 1 0 0 0

0 1 0 0 1

0 0 0 1 0

catch.out

No
No

2 4


【数据范围】

1<=N,p<=300


做题思路(错解):拿到这道题时,以为只要枚举劫匪逃向的区j,然后进行一次BFS,看由j到p经过的点,结果卡在怎么找由j到p经过的点,导致使用了错误的方法。


解题思路(正解):根据题意,依次枚举劫匪逃向的区j和拦截劫匪的区k,每枚举一组j、k,在删除k的情况下,从p点出发进行BFS,看p能否到达j,若能则k不是拦截劫匪的区域,若不能则满足题意输出答案。需要注意的是,在枚举之前,需先从p出发进行BFS,找出p点出发能到的点,如果枚举的区j不能到达p,则直接输出No。


#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#include<queue>#include<vector>using namespace std;const int maxn=305;int N,p;int a[maxn][maxn];vector<int>g[maxn];int vis1[maxn],vis2[maxn];void BFS(int i,int *vis)  //找从i点出发能到达的点{queue<int>q;q.push(i);vis[i]=1;while(!q.empty()){int i=q.front();  q.pop();for(int k=0;k<g[i].size();k++){int j=g[i][k];if(vis[j])  continue;q.push(j);vis[j]=1;}}}int main(){freopen("catch.in","r",stdin);freopen("catch.out","w",stdout);scanf("%d%d",&N,&p);for(int i=1;i<=N;i++)for(int j=1;j<=N;j++)scanf("%d",&a[i][j]);for(int i=1;i<=N;i++)for(int j=i+1;j<=N;j++)if(a[i][j]==1){g[i].push_back(j);g[j].push_back(i);}memset(vis1,0,sizeof(vis1));BFS(p,vis1);  //看p点能到达哪些点for(int i=1;i<=N;i++)if(i!=p){if(vis1[i]==0) //p点不能到达i点{printf("No\n");continue;}int ok=0;for(int j=1;j<=N;j++)if(j!=i && j!=p){memset(vis2,0,sizeof(vis2));vis2[j]=1; //删除j点BFS(p,vis2);if(vis2[i]==0){ok=1;printf("%d ",j);}}if(ok==0)  printf("No");  //如果p点与i点之间有一条直接连通的路,则输出Noprintf("\n");}return 0;}

考后反思:做题时,想得不能太复杂,应该从最简单的暴力枚举开始想,也许有些题就需要用这种方法。如果枚举一个变量不行,就要考虑再枚举一个,不能只停留在只枚举一个变量去找方法解决。在删除条件(假删除)时,应选择最简单删除方法,往往删的方法难了就容易错。考虑问题的情况时,要考虑全面,完整,不能想到一半就开跑。

0 0