Codeforces 1239 D Catowice City —— tarjan

This way

题意:

现在有n个人,n只猫,给你他们的联系,并且第i个人与第i只猫一定有联系。现在需要选出总共n个人+猫,而且至少有一个人,一只猫,问你选的人是哪些,猫是哪些

题解:

第一次接触tarjan,就是求强联通分量的一种方法。
scc相同即在同一个强联通分量里。
那么这道题为什么会扯上scc,是因为我们看到需要n个人+猫,而第i个人与第i只猫一定有联系,说明第i个人与第i只猫中一定要选一个。而如果这张二分图是一个强联通分量的话,由于我们至少需要一个人,但是无论我们取哪个人,都会否决掉至少两只猫,那么又会牵扯上一定要选另一个人,然后又会否决更多的猫,到最后一定是选所有的人。但是我们又至少需要一只猫,所以无法满足条件。
如果有解,那么只要将scc为1的人选出来,剩下的就是猫即可。
选scc为1的是因为scc为1的强联通缩点之后没有出边。

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
struct node{
    int to,next;
}e[N*2];
int cnt,head[N];
void add(int x,int y){
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
// scc
int low[N],dfn[N],scc[N],tim,num;
stack<int>st;
bool in[N];
// init
void init(int siz) {
    memset(head,-1,sizeof(int)*(siz+1));
    cnt=tim=num=0;
    memset(dfn,0,sizeof(int)*(siz+1));
    memset(in,0,sizeof(bool)*(siz+1));
    while(!st.empty())
        st.pop();
}
// deal
void tarjan(int x) {
    low[x]=dfn[x]=++tim;
    st.push(x);
    in[x]=1;
    for(int i=head[x];~i;i=e[i].next) {
        int ne=e[i].to;
        if(!dfn[ne])
            tarjan(ne),low[x]=min(low[x],low[ne]);
        else if(in[ne])
            low[x]=min(low[x],dfn[ne]);
    }
    if(low[x]==dfn[x]) {
        ++num;
        while(1) {
            int v=st.top();
            st.pop();
            scc[v]=num;
            in[v]=0;
            if(x==v)
                break;
        }
    }
}
vector<int>a1,a2;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m;
        scanf("%d%d",&n,&m);
        init(n*2);
        int x,y;
        for(int i=1;i<=m;i++)
            scanf("%d%d",&x,&y),add(x,n+y);
        for(int i=1;i<=n;i++)
            add(n+i,i);
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        if(num==1){
            printf("No\n");
            continue;
        }
        a1.clear(),a2.clear();
        for(int i=1;i<=n;i++)
            if(scc[i]==1)
                a1.push_back(i);
            else
                a2.push_back(i);
        printf("Yes\n");
        printf("%d %d\n",a1.size(),a2.size());
        for(auto i:a1)
            printf("%d ",i);
        printf("\n");
        for(auto i:a2)
            printf("%d ",i);
        printf("\n");
    }
    return 0;
}
/*
1
3 6
1 1
1 2
2 1
2 2
2 3
3 3
*/

发布了530 篇原创文章 · 获赞 31 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/104211627