zoukankan      html  css  js  c++  java
  • 【NOI2017】游戏 题解(2-SAT+缩点)

    题目链接

    题目大意:有四种场地$a,b,c,x$和三种赛车$A,B,C$,$a$不能跑$A$,$b$不能跑$B$,$c$不能跑$C$,$x$都可以跑。给定$n$个场地和$m$个四元组$(i,h_i,j,h_j)$,意为如果在第$i$个场地跑$h_i$,那么第$j$个场地必须跑$h_j$。输出一种合法方案。若无输出$-1$。

    ----------------------------------

    此题难在建图。把建图搞定就是一个裸的2-SAT板子。

    我们规定$0$为每种场地的第一种能跑的车(按字典序),$1$表示第二种能跑的车。对于约束条件,我们有$3$种情况:

    1.$h_i$类型的车与$i$冲突,那么我们直接跳过,不用管它。

    2.$h_j$类型的车与$j$冲突,那么我们让$i$向$i'$连边,表示如果选择$h_i$则无解。

    3.没有冲突情况。那么我们直接按照2-SAT建图方式建就好,即$i$向$j$连边,$j'$向$i'$连边。

    对于$x$,我们只要把它当作某一种特定的场地,然后$dfs$枚举所有情况就好。把它当作任意两种场地就可以包含所有可能情况。

    时间复杂度$O(2^dn)$。

    PS:一开始我超级傻逼,写了一串$if$来判各种情况还各种出锅;后面突然想到只要写个函数判断就行了草。从早上7点来学校写,一直到上午10点才过……

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200005;
    int dfn[maxn],low[maxn],vis[maxn],pos[maxn],jishu,tot;
    stack<int> st;
    int head[maxn],cnt,n,m,d;
    int query[maxn][3];
    char ch[maxn][3],c[maxn],s[maxn];
    struct node
    {
        int next,to;
    }edge[maxn];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void add(int from,int to)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        head[from]=cnt;
    }
    inline void clear()
    {
        jishu=tot=cnt=0;
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(pos,0,sizeof(pos));
        while(!st.empty()) st.pop();
    }
    inline void tarjan(int now)
    {
        dfn[now]=low[now]=++jishu;
        st.push(now);vis[now]=1;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (!dfn[to]) tarjan(to),low[now]=min(low[now],low[to]);
            else if (vis[to]) low[now]=min(low[now],dfn[to]);
        }
        if (low[now]==dfn[now])
        {
            tot++;
            while(st.top()!=now)
            {
                int x=st.top();st.pop();
                vis[x]=0;
                pos[x]=tot;
            }
            int x=st.top();st.pop();
            vis[x]=0;
            pos[x]=tot;
        }
    }
    inline bool check(int pos,char x)
    {
        if (x+32==s[pos]) return 1;
        return 0;
    }
    inline bool get(int pos,char x)
    {
        if (s[pos]=='a') return x=='B'?0:1; 
        else return x=='A'?0:1;
    }
    inline void dfs(int now)
    {
        if (now>n)
        {
            clear();
            for (int i=1;i<=m;i++)
            {
                int a=query[i][1],b=query[i][2];
                if (check(a,ch[i][1])) continue;
                if (check(b,ch[i][2]))
                {
                    int flag=get(a,ch[i][1]);
                    if (!flag) add(a,a+n);
                    else add(a+n,a);
                    continue;
                }
                else
                {
                    int x=get(a,ch[i][1]),y=get(b,ch[i][2]);
                    if (x==0&&y==0) add(a,b),add(b+n,a+n);
                    if (x==0&&y==1) add(a,b+n),add(b,a+n);
                    if (x==1&&y==0) add(a+n,b),add(b+n,a);
                    if (x==1&&y==1) add(a+n,b+n),add(b,a);
                }
            }
            for (int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
            for (int i=1;i<=n;i++) if (pos[i]==pos[i+n]) return;
            for (int i=1;i<=n;i++)
            {
                if (pos[i]<pos[i+n])
                {
                    if (s[i]=='a') printf("B");
                    else printf("A");
                }
                else
                {
                    if (s[i]=='c') printf("B");
                    else printf("C");
                }
            }
            exit(0);
        }
        if (c[now]=='a') s[now]='a',dfs(now+1);
        if (c[now]=='b') s[now]='b',dfs(now+1);
        if (c[now]=='c') s[now]='c',dfs(now+1);
        if (c[now]=='x'){s[now]='a',dfs(now+1);s[now]='b',dfs(now+1);}
    }
    int main()
    {
        n=read(),d=read();
        cin>>(c+1);
        m=read();
        for (int i=1;i<=m;i++)
        {
            query[i][1]=read(),cin>>ch[i][1];
            query[i][2]=read(),cin>>ch[i][2];
        }
        dfs(1);
        printf("-1");
        return 0;
    }
  • 相关阅读:
    RabbitMQ In JAVA 介绍及使用
    JSON Web Token 入门教程
    char* 与 char[] 的区别
    C++ namespace的用法
    启动其他APK的Activity方法 (转至http://www.cnblogs.com/lijunamneg/archive/2013/02/26/2934060.html)
    Android多任务切换与Activity启动模式SingleTask之间关系的分析
    对SingleTask和TaskAffinity的理解(转至 http://www.2cto.com/kf/201311/254450.html)
    正在运行的android程序,按home键之后退回到桌面,在次点击程序图标避免再次重新启动程序解决办法
    大牛的博客
    Androidpn 简单实现及分析
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13405647.html
Copyright © 2011-2022 走看看