RQNOJ190 拦截匪徒 (重庆一中高2018级信息学竞赛测验2) 解题报告
2016-07-14 15:36
239 查看
【问题描述】
某城市的地图是一个由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
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。
考后反思:做题时,想得不能太复杂,应该从最简单的暴力枚举开始想,也许有些题就需要用这种方法。如果枚举一个变量不行,就要考虑再枚举一个,不能只停留在只枚举一个变量去找方法解决。在删除条件(假删除)时,应选择最简单删除方法,往往删的方法难了就容易错。考虑问题的情况时,要考虑全面,完整,不能想到一半就开跑。
某城市的地图是一个由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
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点之间有一条直接连通的路,则输出No printf("\n"); } return 0; }
考后反思:做题时,想得不能太复杂,应该从最简单的暴力枚举开始想,也许有些题就需要用这种方法。如果枚举一个变量不行,就要考虑再枚举一个,不能只停留在只枚举一个变量去找方法解决。在删除条件(假删除)时,应选择最简单删除方法,往往删的方法难了就容易错。考虑问题的情况时,要考虑全面,完整,不能想到一半就开跑。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C++的template模板中class与typename关键字的区别分析
- C与C++之间相互调用实例方法讲解