zoukankan      html  css  js  c++  java
  • hdu 4685(强连通分量+二分图)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4685

    题意:n个王子和m个公主,王子只能和他喜欢的公主结婚,公主可以和所有的王子结婚,输出所有王子可能的结婚对象,

    必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了。

    分析:这题是poj 1904的加强版,poj 1904的王子和公主数是相等的,这里可以不等,且poj 1904给出了一个初始完美匹配,但是这题就要自己求。

    所以只要求出完美匹配之后,就和poj 1904的做法就完全相同了,这里就不在赘述了,可以参考:http://www.cnblogs.com/frog112111/p/3384261.html

    那么怎么求出完美匹配呢?一开始我用多重匹配的匈牙利算法来做,但是怎么做都不对.......看了题解才恍然大悟=_=

    先说几个坑,这题有点奇怪,就是所有王子都可以争着和同一个公主结婚,只要该王子喜欢该公主,感觉公主有点悲哀呀........

    比如:2 2

            1 1

            1 1

          

    输出的答案是:1 1   而不是  1 1

                        1 1             0        

    这里就是和poj 1904有点不一样的地方,坑了我好久.........

    求完美匹配:

    先对原图用匈牙利算法做一遍二分图匹配,但是还有可能剩余一些人还没匹配,只要虚拟出一些节点来匹配剩余的点就行了

    假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。

    假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主

    这样就构成完美匹配了,接下来就是和poj 1904一样了。

    注意:虽然n和m才500,但是数组要开到2000才能过,可能是剩余太多顶点没匹配,所以要虚拟出比较多的顶点吧,我只开到1500,wa到死=_=

    还有就是一些细节没处理好也贡献了好多wa,做了一天.........快奔溃了,最后参考别人的代码改来改去才AC,好艰辛,不过最终能过也算安慰了

    果然想问题还是不够周全,不够细心

    大三了都,哎,弱成一坨翔了~

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 using namespace std;
      5 const int N=2000;
      6 const int M=1000000+3000;
      7 struct EDGE{
      8     int v,next;
      9 }edge[M];
     10 int first[N],low[N],dfn[N],sta[M],belong[N];
     11 int ans[N],match[N],flag[N];
     12 bool instack[N],vis[N];
     13 int n,m,g,cnt,top,scc,maxn;
     14 int Scan()      //输入外挂
     15 {
     16     int res=0,ch,flag=0;
     17     if((ch=getchar())=='-')
     18         flag=1;
     19     else if(ch>='0'&&ch<='9')
     20         res=ch-'0';
     21     while((ch=getchar())>='0'&&ch<='9')
     22         res=res*10+ch-'0';
     23     return flag?-res:res;
     24 }
     25 void Out(int a)    //输出外挂
     26 {
     27     if(a>9)
     28         Out(a/10);
     29     putchar(a%10+'0');
     30 }
     31 void AddEdge(int u,int v)
     32 {
     33     edge[g].v=v;
     34     edge[g].next=first[u];
     35     first[u]=g++;
     36 }
     37 int min(int a,int b)
     38 {
     39     return a<b?a:b;
     40 }
     41 int max(int a,int b)
     42 {
     43     return a>b?a:b;
     44 }
     45 void init()
     46 {
     47     g=cnt=top=scc=0;
     48     memset(first,-1,sizeof(first));
     49     memset(dfn,0,sizeof(dfn));
     50     memset(instack,false,sizeof(instack));
     51     memset(flag,0,sizeof(flag));
     52     //scanf("%d%d",&n,&m);
     53     n=Scan();
     54     m=Scan();
     55     maxn=max(n,m);    //王子和公主数可能不同,为了建图方便去较大者,王子编号1--maxn,公主编号maxn+1--2*maxn
     56 }
     57 bool dfs(int u)
     58 {
     59     int i,v;
     60     for(i=first[u];i!=-1;i=edge[i].next)
     61     {
     62         v=edge[i].v;
     63         if(!vis[v])
     64         {
     65             vis[v]=true;
     66             if(match[v]==0||dfs(match[v]))
     67             {
     68                 match[v]=u;
     69                 flag[u]=v;
     70                 return true;
     71             }
     72         }
     73     }
     74     return false;
     75 }
     76 void xiong()    //二分匹配
     77 {
     78     int i;
     79     memset(match,0,sizeof(match));
     80     for(i=1;i<=maxn;i++)
     81     {
     82         memset(vis,false,sizeof(vis));
     83         dfs(i);
     84     }
     85 }
     86 void Tarjan(int u)     //求强连通分量
     87 {
     88     int i,v;
     89     low[u]=dfn[u]=++cnt;
     90     sta[++top]=u;
     91     instack[u]=true;
     92     for(i=first[u];i!=-1;i=edge[i].next)
     93     {
     94         v=edge[i].v;
     95         if(!dfn[v])
     96         {
     97             Tarjan(v);
     98             low[u]=min(low[u],low[v]);
     99         }
    100         else if(instack[v])
    101             low[u]=min(low[u],dfn[v]);
    102     }
    103     if(low[u]==dfn[u])
    104     {
    105         scc++;
    106         while(1)
    107         {
    108             v=sta[top--];
    109             instack[v]=false;
    110             belong[v]=scc;
    111             if(u==v)
    112                 break;
    113         }
    114     }
    115 }
    116 void build()
    117 {
    118     int i,k,v,j;
    119     for(i=1;i<=n;i++)
    120     {
    121     //    scanf("%d",&k);
    122         k=Scan();
    123         while(k--)
    124         {
    125         //    scanf("%d",&v);
    126             v=Scan();
    127             AddEdge(i,v+maxn);    //王子和喜欢的公主之间连边
    128         }
    129     }
    130 
    131     xiong();   //做一次二分匹配
    132 
    133     int all=2*maxn;
    134     for(i=1;i<=maxn;i++)    //为剩余王子匹配虚拟公主
    135     {
    136         if(!flag[i])
    137         {
    138             all++;
    139             for(j=1;j<=maxn;j++)  //所有王子都喜欢该虚拟公主
    140                 AddEdge(j,all);
    141             match[all]=i;
    142             flag[i]=all;
    143         }
    144     }
    145 
    146     for(i=maxn+1;i<=2*maxn;i++)    //为剩余公主匹配虚拟王子
    147     {
    148         if(!match[i])
    149         {
    150             all++;
    151             for(j=maxn+1;j<=2*maxn;j++)   //该虚拟王子喜欢所有公主
    152                 AddEdge(all,j);
    153             flag[all]=i;
    154             match[i]=all;
    155         }
    156     }
    157     for(i=1;i<=all;i++)    //所有与王子匹配的公主建一条边连向王子
    158     {
    159         if(flag[i])
    160             AddEdge(flag[i],i);
    161     }
    162 }
    163 void solve()
    164 {
    165     int i,u,v;
    166     for(i=1;i<=maxn;i++)   //求强连通分量
    167         if(!dfn[i])
    168             Tarjan(i);
    169 
    170     for(u=1;u<=n;u++)  //枚举所有王子
    171     {
    172         int count=0;
    173         for(i=first[u];i!=-1;i=edge[i].next)
    174         {
    175             v=edge[i].v;
    176             if(belong[u]==belong[v])    //王子与公主同在一个强连通分量
    177             {
    178                 if(v-maxn>m)
    179                     continue;
    180                 ans[count++]=v-maxn;
    181             }
    182         }
    183         sort(ans,ans+count);
    184     //    printf("%d",count);
    185         Out(count);
    186         for(i=0;i<count;i++)      //输出
    187         {
    188             //printf(" %d",ans[i]);
    189             putchar(' ');
    190             Out(ans[i]);
    191         }
    192     //    printf("
    ");
    193         putchar('
    ');
    194     }
    195 }
    196 int main()
    197 {
    198     int t,cas;;
    199 //    scanf("%d",&t);
    200     t=Scan();
    201     for(cas=1;cas<=t;cas++)
    202     {
    203         init();
    204         build();
    205         printf("Case #%d:
    ",cas);
    206         solve();
    207     }
    208     return 0;
    209 }
    View Code
  • 相关阅读:
    高性能 HTML5 地铁样式的应用程序中的内容
    微软披露更多ARM Win8细节
    下一代互联网搜索的前沿:意图、知识与云
    使用 Sphinx 更好地进行 MySQL 搜索使用 Sphinx 进行非全文本搜索
    如何加快数模计算以及如何解决数模计算的收敛性问题
    Google App Engine正式支持Python 2.7
    ASP.NET MVC模型绑定
    给 MySQL 增加 Sequence 管理功能
    使用 Rational Build Forge 自动化 IBM Cloud 上的构建和发布过程
    Windows Phone 8基于WinRT?
  • 原文地址:https://www.cnblogs.com/frog112111/p/3387173.html
Copyright © 2011-2022 走看看