BZOJ5012[ioi2017]Train

版权声明:...............转载说一声并注明出处qaq............... https://blog.csdn.net/L_0_Forever_LF/article/details/80747397

下面定义的能走到/不能走到都是在A,B采取最优决策下的

因为充一次电能跑n个点,所以A胜利的条件就是能走到一个有充电站的环,B反之

如果一个充电车站不能走到任何一个充电车站(包括自己),那么我们可以把它视为不能充电的
我们不断bfs求出哪些充电车站不能被其他充电走到,然后去掉他们,重复这个过程直到图中剩余所有充电车站都可以到达一个充电车站
然后看起点是否能走到某个充电车站就知道是否A赢了

bfs用博弈定义下的bfs倒着做,具体来说:
对每个充电车站求出一个能走到这个充电车站的集合S
然后对于其他点
如果他被A控制且有指向S的出边就把他加入S
如果他被B控制且所有出边都指向S就把他加入S
(注意这个充电车站要特殊处理)
不断加点直到无点可加

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define pb push_back
#define SZ(x) ((int)x.size())
using namespace std;

const int maxn = 5100;
const int maxm = 210000;

int n,m;
int col[maxn],s[maxn],d[maxn];
vector<int>E[maxn],iE[maxn];

int ok[maxn],nd[maxn];
queue<int>q;

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++) scanf("%d",&col[i]);
    for(int i=0;i<n;i++) scanf("%d",&s[i]);
    for(int i=1;i<=m;i++)
    {
        int x,y; scanf("%d%d",&x,&y);
        d[x]++;
        E[x].pb(y); iE[y].pb(x);
    }

    int mark=1;
    while(mark)
    {
        mark=0;
        for(int i=0;i<n;i++) ok[i]=0,nd[i]=d[i];
        for(int i=0;i<n;i++) if(s[i])
        {
            for(int j=0;j<SZ(iE[i]);j++)
            {
                int p=iE[i][j];
                nd[p]--;
                if(!ok[p]&&(col[p]||!nd[p])) q.push(p),ok[p]=1;
            }
        }
        while(!q.empty())
        {
            const int y=q.front(); q.pop();
            if(s[y]) continue;

            for(int j=0;j<SZ(iE[y]);j++)
            {
                int x=iE[y][j];
                nd[x]--;
                if(!ok[x]&&(col[x]||!nd[x])) q.push(x),ok[x]=1;
            }
        }

        for(int i=0;i<n;i++) if(s[i])
        {
            if(!ok[i]) mark=1;
            s[i]&=ok[i];
        }
    }
    for(int i=0;i<n;i++) printf("%d%c",ok[i],i!=n-1?' ':'\n');

    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页