计蒜客(2017 ICPC Mid-Central USA Region)G. Faulty Robot

G. Faulty Robot

题意: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;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值