• poj 1904 King's Quest


    King's Quest

    题意:有N个王子和N个妹子;(1 <= N <= 2000)第i个王子喜欢Ki个妹子;(详见sample)题给一个完美匹配,即每一个王子和喜欢的一个妹子结婚;问每一个王子可以有几种选择(在自己喜欢的妹子里面选),并输出可选的妹子的标号(升序);

    Sample Input

    4 (N)
    2 1 2  (Ki)
    2 1 2
    2 2 3
    2 3 4
    1 2 3 4 (完美匹配)
    

    Sample Output

    2 1 2
    2 1 2
    1 3
    1 4
    

    分析:图匹配问题,1~N为王子的编号,N~2N为妹子的编号;输入有向边;

    重点: 对于给定的一组匹配,看做是反向边;即从妹子指回到王子;这样进行Tarjan缩点之后,就可以遍历边(要在王子喜欢的妹子的选...)看是否还在同一个强连通分量中,若妹子还是和王子在同一个scc中,即可婚配;

    证明:为什么说还在一个强连通分量中就可以?边一定是连接王子和妹子的,在不重复走一条边的前提下,会知道王子和妹子的个数是相同的;并且每条边都符合王子喜欢妹子的条件;

    ps:该题第一次使用了输出外挂,很好用啊!!时间之间减了至少1/10...

    思维坑点:认为可以直接在Tarjan缩点时,就把每个强连通分量里面的妹子写入vec[]中;这样之后就可以直接对每个vec排序之后,之后调用belong[]输出所在的scc的个数即妹子的编号。。想法是好的,但是题意啊!!!并不是在一个连通分量的妹子都是这样王子喜欢的。。。所以要遍历边,找到在一个连通分量里面的;

    // 532ms 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    #include<stack>
    #include<set>
    using namespace std;
    #define rep0(i,l,r) for(int i = (l);i < (r);i++)
    #define rep1(i,l,r) for(int i = (l);i <= (r);i++)
    #define rep_0(i,r,l) for(int i = (r);i > (l);i--)
    #define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
    #define MS0(a) memset(a,0,sizeof(a))
    #define MS1(a) memset(a,-1,sizeof(a))
    #define pb push_back
    template<typename T>
    void read(T &m)
    {
        T x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        m = x*f;
    }
    template<typename T>
    void out(T a)
    {
        if(a>9) out(a/10);
        putchar(a%10+'0');
    }
    const int N = 2020<<1;//倍增点数
    const int M = 202200;
    int head[M],tot;
    struct edge{
        int to,w,Next;
    }e[M];
    void ins(int a,int b,int w = 0)
    {
        e[++tot].Next = head[a];
        e[tot].to = b;
        e[tot].w = w;
        head[a] = tot;
    }
    int pre[N],dfs_clock,low[N];
    int belong[N],scc,n;
    stack<int> S;
    bool stk[N];
    void Tarjan(int u)
    {
        pre[u] = low[u] = ++dfs_clock;
        S.push(u);
        stk[u] = true;
        int v;//点u所在连通分量的出度;
        for(int i = head[u];i;i = e[i].Next){
            v = e[i].to;
            if(pre[v] == 0){
                Tarjan(v);
                low[u] = min(low[u],low[v]);
            }else if(stk[v]){
                low[u] = min(low[u],pre[v]);
            }
        }
        if(pre[u] == low[u]){//强连通分量的根节点
            ++scc;
            do{
                v = S.top();
                S.pop();stk[v] = false;
                //if(v <= n)
                belong[v] = scc;
                //else vec[scc].pb(v);
            }while(v != u);
        }
    }
    int ans[N];
    int main()
    {
        int v,T,kase = 1;
        read(n);
        rep1(u,1,n){
            int k;
            read(k);
            rep0(j,0,k){
                read(v);
                ins(u,v+n);//妹子标号要加上n;
            }
        }
        rep1(u,1,n){
            read(v);
            ins(v+n,u);//反向边***
        }
        rep1(u,1,n)if(pre[u] == 0)
            Tarjan(u);
        rep1(u,1,n){
            int cnt = 0;
                 for(int i = head[u];i;i = e[i].Next){//遍历边
                     v=e[i].to;
                     if(belong[u] == belong[v])   //同一个强连通分量
                         ans[cnt++] = v-n;
                 }
                 sort(ans,ans+cnt);
                 out(cnt);
                 rep0(i,0,cnt){
                     putchar(' ');
                     out(ans[i]);
                 }
                 puts("");
            }
        return 0;
    }
    View Code
  • 相关阅读:
    (转)Dockerfile安全介绍
    (转)浅析Docker运行安全
    (转)网络安全设备默认密码
    docker kali 相关初始化工作
    hibernate(结合springboot)入门
    idea 通过 Generate POJOs.groovy 生成实体类
    linux jdk 安装
    docker pstgres安装
    使用docker搭建FastDFS文件系统
    [docker]离线环境导入镜像
  • 原文地址:https://www.cnblogs.com/hxer/p/5186495.html
Copyright © 2020-2023  润新知