题解 洛谷 P6378 【[PA2010]Riddle】

首先不难看出对于本题的点与点之间的限制关系,我们可以考虑用(2-SAT)来解决,通过从状态(x)向状态(y)连一条有向边表示若状态(x)存在,那么状态(y)必须存在。

接下来的处理中,(x)表示点(x)被选为关键点,(x^prime)表示点(x)没有选为关键点,(x longrightarrow y)表示两个状态之间连一条有向边。

对于每条边至少有一个端点是关键点这一限制,若边两端为(x)(y),那么直接进行(x^prime longrightarrow y , y^prime longrightarrow x)即可。

处理使得每个部分恰有一个关键点这一限制时,发现要进行像一个点向该部分中除它以外的所有点连边的操作,这样的话,边数会达到(n^2)级别,这是不可以接受的,所以要考虑优化建图。

对于每个点,我们这里在其所在的部分中考虑,每个点用(a_i)来表示,再对其新增一个状态(pre_i),表示在该部分中前(i)个点是否有点被选为关键点。

连边时我们可以进行以下的操作:

(a_i longrightarrow pre_{a_i} , pre_{a_i}^prime longrightarrow a_i^prime)

$pre_{a_{i-1}} longrightarrow pre_{a_i} , pre_{a_i}^prime longrightarrow pre_{a_{i-1}}^prime $

( pre_{a_{i-1}} longrightarrow a_i^prime , a_i longrightarrow pre_{a_{i-1}}^prime)

通过这样的前缀优化建图,就不用再连那么多边了,同时题目的限制条件也都可以满足。

具体实现细节看代码吧。

(code:)

#include<bits/stdc++.h>
#define p1(x) x
#define p0(x) x+n
#define pre1(x) x+2*n
#define pre0(x) x+3*n
#define maxn 8000010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,k,dfn_cnt,co_cnt,top;
int dfn[maxn],low[maxn],co[maxn],st[maxn],a[maxn];
bool vis[maxn];
struct edge
{
    int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
    e[++edge_cnt]=(edge){to,head[from]};
    head[from]=edge_cnt;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++dfn_cnt;
    st[++top]=x,vis[x]=true;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
        else if(vis[y]) low[x]=min(low[x],dfn[y]);
    }
    if(low[x]==dfn[x])
    {
        co_cnt++;
        int now;
        do
        {
            now=st[top--];
            vis[now]=false;
            co[now]=co_cnt;
        }while(now!=x);
    }
}
bool check()
{
    for(int i=1;i<=4*n;++i)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;++i)
        if(co[p1(i)]==co[p0(i)]||co[pre1(i)]==co[pre0(i)])
            return false;
    return true;
}
int main()
{
    read(n),read(m),read(k);
    for(int i=1;i<=m;++i)
    {
        int x,y;
        read(x),read(y);
        add(p0(x),p1(y)),add(p0(y),p1(x));
    }
    for(int i=1;i<=k;++i)
    {
        int w;
        read(w);
        for(int j=1;j<=w;++j)
            read(a[j]),add(p1(a[j]),pre1(a[j])),add(pre0(a[j]),p0(a[j]));
        for(int j=2;j<=w;++j)
        {
            add(pre1(a[j-1]),pre1(a[j])),add(pre0(a[j]),pre0(a[j-1]));
            add(pre1(a[j-1]),p0(a[j])),add(p1(a[j]),pre0(a[j-1]));
        }
    }
    if(check()) puts("TAK");
    else puts("NIE");
    return 0;
}
原文地址:https://www.cnblogs.com/lhm-/p/12695332.html