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

【问题描述】
某城市的地图是一个由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点之间有一条直接连通的路,则输出No
		printf("\n");
	}
	return 0;
}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值