题意:n个节点、m条边构成一个有向图,再输入m行,每行包含a、b两个数。
若a>0,则a->b为一条普通边;若a<0,则(-a)->b为一条特殊边。
节点1为起始点,只能走特殊边;若该点出了bug,则既可以走特殊边也可以走普通边。
节点处可能出bug,所有节点最多只能出一次bug。
问:有多少个节点你可能会被迫停止,无法继续走。
思路:广搜。
用一个数s表示还剩几个bug可以出现:
s=0代表已经出现了一次bug,剩余0个bug可以出;
s=1代表还未出现过bug,剩余1个bug可以出。
若该节点既没有特殊边也没有普通边,则无法继续走。
s=0时,若该节点没有特殊边,则无法继续走,ans++;若该节点有特殊边,则可以继续走。
s=1时,若该节点没有特殊边,且该节点没有出bug,则无法继续走,ans++;若该节点没有特殊边,有普通边,且该节点出了bug,则可以继续走,s更新为0。
代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <cstdio>
#include <vector>
#include <string>
#include <cmath>
#include <stack>
#include <queue>
#include <map>
#include <set>
#define INF 0x3f3f3f3f
#define fori(a,b) for(LL i=a;i<=b;i++)
#define forj(a,b) for(LL j=a;j<=b;j++)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
const double PI = acos(-1);
const LL M = 1e3+10;
//const LL MM = 1e5+10;
vector<int>v[M],vv[M];
int vis[M],ans=0,num[M];
//v[M] 存普通边,vv[M] 存特殊边
//vis[M]=1 代表节点M已经搜过
//num[M]=1 代表节点M可能无法继续走,答案中已经把节点M加上
void _fs(int n,int s)
{
//s=0且该节点没有特殊边,无法继续走
if(s==0&&vv[n].size()==0){
if(!num[n]){
ans++;
num[n]=1;
}
return ;
}
//该节点既没有特殊边也没有普通边,无法继续走
if(!v[n].size()&&!vv[n].size()){
if(!num[n]){
ans++;
num[n]=1;
}
return ;
}
//s=0,若该节点有特殊边,则可以继续走
if(s==0){
for(int i=0;i<vv[n].size();i++){
if(!vis[vv[n][i]]){
vis[vv[n][i]]=1;
_fs(vv[n][i],0);
vis[vv[n][i]]=0;
}
}
}
//s=1
else {
//若该点出bug,s更新为0,走普通边
for(int i=0;i<v[n].size();i++){
if(!vis[v[n][i]]){
vis[v[n][i]]=1;
_fs(v[n][i],0);
vis[v[n][i]]=0;
}
}
//若该点不出bug,且没有特殊边,则无法继续走
if(vv[n].size()==0){
if(!num[n]){
ans++;
num[n]=1;
}
return ;
}
//若该点不出bug,有特殊边,则可以继续走
for(int i=0;i<vv[n].size();i++){
if(!vis[vv[n][i]]){
vis[vv[n][i]]=1;
_fs(vv[n][i],1);
vis[vv[n][i]]=0;
}
}
}
return ;
}
int main()
{
int n,m;
mem(vis,0);
mem(num,0);
cin >> n >> m;
for(int i=1;i<=m;i++){
int a,b;
cin >> a >> b;
if(a>0){
v[a].push_back(b);
}
else {
vv[-a].push_back(b);
}
}
_fs(1,1);
cout << ans << endl;
return 0;
}