• poj 1904(强连通分量+输入输出外挂)


    题目链接:http://poj.org/problem?id=1904

    题意:有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国王不满意,他要求大臣给他另一个表,每个王子可以和几个妹子结婚,按序号升序输出妹子的编号,这个表应满足所有的王子最终都有妹子和他结婚。

    分析:很好的图论题,把强连通分量和完美匹配结合起来了,记得多校的时候看到类似的题目(hdu 4685),但是不会做,还以为是二分匹配=_=

    首先建图,如果王子u喜欢妹子v,则建一条边u指向v(u,v),对于大臣给出的初始完美匹配,如果王子u和妹子v结婚,则建一条边v指向u(v,u),然后求强连通分量,

    对于每个王子和妹子,如果他们都在同一个强连通分量内,则他们可以结婚。

    为什么呢?因为每个王子只能和喜欢的妹子结婚,初始完美匹配中的丈夫和妻子之间有两条方向不同的边可以互达,则同一个强连通分量中的王子数和妹子数一定是相等的,若王子x可以和另外的一个妹子a结婚,妹子a的原配王子y肯定能找到另外一个妹子b结婚,因为如果找不到的话,则x和a必不在同一个强连通分量中。

    所以一个王子可以和所有与他同一强连通分量的妹子结婚,而这不会导致同一强连通分量中的其他王子找不到妹子结婚。

    好像很绕的样子@_@。。。。。大家在纸上画画图吧

    建图的时候王子从1~n编号,妹子从n+1~2*n编号

    这一题的数据量挺大的,光是输入输出就会消耗很多时间了,可以用输入输出外挂来加速读入和输出。

    不加输入外挂9000+ms

    加输入外挂8000+ms

    加输入输出外挂500+ms

    AC代码:

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 
      6 const int N=4000+5;
      7 const int M=200000+4000;
      8 struct EDGE{
      9     int v,next;
     10 }edge[M];
     11 int first[N],low[N],dfn[N],sta[M],belong[N],ans[N];
     12 bool instack[N];
     13 int g,cnt,top,scc;
     14 
     15 void AddEdge(int u,int v)
     16 {
     17     edge[g].v=v;
     18     edge[g].next=first[u];
     19     first[u]=g++;
     20 }
     21 int min(int a,int b)
     22 {
     23     return a<b?a:b;
     24 }
     25 void Tarjan(int u)    //求强连通分量
     26 {
     27     int i,v;
     28     low[u]=dfn[u]=++cnt;
     29     sta[++top]=u;
     30     instack[u]=true;
     31     for(i=first[u];i!=-1;i=edge[i].next)
     32     {
     33         v=edge[i].v;
     34         if(!dfn[v])
     35         {
     36             Tarjan(v);
     37             low[u]=min(low[u],low[v]);
     38         }
     39         else if(instack[v])
     40             low[u]=min(low[u],dfn[v]);
     41     }
     42     if(low[u]==dfn[u])
     43     {
     44         scc++;
     45         while(1)
     46         {
     47             v=sta[top--];
     48             instack[v]=false;
     49             belong[v]=scc;    //缩点
     50             if(u==v)
     51                 break;
     52         }
     53     }
     54 }
     55 int Scan()     //输入外挂
     56 {
     57     int res=0,ch,flag=0;
     58     if((ch=getchar())=='-')
     59         flag=1;
     60     else if(ch>='0'&&ch<='9')
     61         res=ch-'0';
     62     while((ch=getchar())>='0'&&ch<='9')
     63         res=res*10+ch-'0';
     64     return flag?-res:res;
     65 }
     66 void Out(int a)    //输出外挂
     67 {
     68     if(a>9)
     69         Out(a/10);
     70     putchar(a%10+'0');
     71 }
     72 int main()
     73 {
     74     int n,i,u,v,k;
     75     while(scanf("%d",&n)!=EOF)
     76     {
     77         g=cnt=top=scc=0;
     78         memset(first,-1,sizeof(first));
     79         memset(dfn,0,sizeof(dfn));
     80         memset(instack,false,sizeof(instack));
     81         for(i=1;i<=n;i++)
     82         {
     83         //    scanf("%d",&k);
     84             k=Scan();
     85             while(k--)
     86             {
     87             //    scanf("%d",&v);
     88                 v=Scan();
     89                 AddEdge(i,v+n);      //王子i喜欢妹子v
     90             }
     91         }
     92         for(i=1;i<=n;i++)
     93         {
     94         //    scanf("%d",&v);
     95             v=Scan();
     96             AddEdge(v+n,i);       //王子i可以和妹子v结婚
     97         }
     98 
     99         for(i=1;i<=2*n;i++)    //求强连通分量
    100             if(!dfn[i])
    101                 Tarjan(i);
    102 
    103         for(u=1;u<=n;u++)
    104         {
    105             int count=0;
    106             for(i=first[u];i!=-1;i=edge[i].next)
    107             {
    108                 v=edge[i].v;
    109                 if(belong[u]==belong[v])   //同一个强连通分量
    110                     ans[count++]=v-n;
    111             }
    112             sort(ans,ans+count);
    113         //    printf("%d",count);
    114             Out(count);
    115             for(i=0;i<count;i++)
    116             {
    117                 //printf(" %d",ans[i]);
    118                 putchar(' ');
    119                 Out(ans[i]);
    120             }
    121         //    printf("
    ");
    122             putchar('
    ');
    123         }
    124     }
    125     return 0;
    126 }
    View Code
  • 相关阅读:
    js 获取和设置css3 属性值的实现方法
    API的自动化测试
    删除html标签或标签属性以及样式
    JS+CSS实现数字滚动
    video元素和audio元素相关事件
    SDT v0.0.1 上线
    safari浏览器fixed后,被软键盘遮盖的问题—【未解决】
    js中DOM事件探究
    使用Web存储API存取本地数据
    剑指offer(Java版)第七题:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead, 分别完成在队列尾部插入结点和在队列头部删除结点的功能。
  • 原文地址:https://www.cnblogs.com/frog112111/p/3384261.html
Copyright © 2020-2023  润新知