【问题描述】
某城市的地图是一个由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的顺序输出,若有多点,由小到大顺序输出,如没有则输出No。
【输入样例】
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
【输出样例】
No
No
2
2 4
【数据范围】
1<=n,p<=300
【思路梳理】
没有太多技术含量,对于歹徒的逃跑路线p->j如果警察埋伏在k点使得能够将匪徒抓获,那么就是说删除掉节点k后p与j不再连通。因为数据不大,所以可对于每一个节点都进行穷举,判断删除某个节点k后p与j是否连通,如果不能连通,那么k就是一个可以抓获歹徒的点。
【Cpp代码】
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#define maxn 305
using namespace std;
int n,p;
vector<int>g[maxn];
bool vis[maxn],d[maxn];
void DFS(int i)
{
d[i]=true;
for(int j=0;j<g[i].size();j++)
{
int k=g[i][j];
if(d[k]) continue;
DFS(k);
}
}
bool BFS(int e,int ignore)
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(p);
vis[p]=true;
while(!q.empty())
{
int i=q.front();q.pop();
if(i==e) return true;
for(int j=0;j<g[i].size();j++)
{
int k=g[i][j];
if(k==ignore || vis[k]) continue;
q.push(k);
vis[k]=true;
}
}
return false;
}
int main()
{
//freopen("in.txt","r",stdin);
cin>>n>>p;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
int x;
scanf("%d",&x);
if(x==1) g[i].push_back(j);
}
memset(d,0,sizeof(d));
DFS(p);
for(int i=1;i<=n;i++)if(i!=p)
{
bool ok=false;
if(d[i])
{
for(int j=1;j<=n;j++)
{
if(j==p || j==i) continue;
if(!BFS(i,j))
{
ok=true;
printf("%d ",j);
}
}
}
if(!ok) printf("No");
printf("\n");
}
return 0;
}