poj 1904

来源:互联网 发布:钢琴入门自学教程知乎 编辑:程序博客网 时间:2024/04/30 15:32

      题目意思:有N对男女,一个男的可以喜欢多个女的,要求这样一个匹配,使得一个男的尽可以多的和他喜欢的女的结婚,同时保证所有男的均有伴侣。

      这题不是二分图匹配,但是考查了二分图匹配的思想,按照这个思想建图即可解决。首先是按照题中的要求,对于每对男女u,v,连边(u,v+n),n为对数,最后给出的那个匹配是正确的,则对于每个女生v,连边(v,u),u为男生。然后求强连通分量,对于每个男生,所有和他在同一个强连通分量里的女生都可以做他的老婆,只要计数排好序输出即可。

      之所以说考察了二分图匹配的思想,是因为这里考查了匈牙利算法的找增广路的过程,大家可以照着这个图,模拟匈牙利算法,就可以明白。它是在保证了前一个结点有匹配的基础上,找到自己的匹配。如样例中的1号男生,他若选了2号女生,则同一个强连通分量里的2号男生可以顺着“增广边”(5->1)找到1号女生,则一过程实际就是匈牙利算法找增广路的过程。

     以下是代码,3000+ms,不知牛人是怎样300+ms的,因为数据量很大。

 

  1. #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int M=400110;
    const int N=4200;
    struct node
    {
     int v;
     int next;
    }edge[M];
    int head[N],num;
    bool vis[N],instack[N];
    int stack[10*N],belong[N],top,bcnt,dindex,dep[N],low[N];
    int n,m;
  2. void init()
    {
     int i;
     for(i=0;i<=2*n+5;i++)
      head[i]=-1;
     num=0;
    }
  3. void addege(int u,int v)
    {
     edge[num].v=v;
     edge[num].next=head[u];
     head[u]=num++;
    }
  4. void dfs(int i)
    {
     int j,v;
     dep[i]=low[i]=++dindex;
     instack[i]=1;
     stack[++top]=i;
     for(j=head[i];j!=-1;j=edge[j].next)
     {
      v=edge[j].v;
      if(!dep[v])
      {
       dfs(v);
       if(low[v]<low[i])
        low[i]=low[v];
      }
      else if(instack[v] && dep[v]<low[i])
       low[i]=dep[v];
     }
     if(dep[i]==low[i])
     {
      bcnt++;
      do
      {
       j=stack[top--];
       instack[j]=0;
       belong[j]=bcnt;
      }while(j!=i);
     }
    }
  5. void tarjan()
    {
     int i;
     top=bcnt=dindex=0;
     memset(dep,0,sizeof(dep));
     memset(vis,0,sizeof(vis));
     for(i=1;i<=n;i++)
      if(!dep[i])
      {
       dfs(i);
      }
    }
  6. int rec[N];
    void solve()
    {
     int i,j,cnt;
     for(i=1;i<=n;i++)
     {
      cnt=0;
      for(j=head[i];j!=-1;j=edge[j].next)
       if(belong[edge[j].v]==belong[i])
        rec[cnt++]=edge[j].v-n;
      sort(rec,rec+cnt);
      printf("%d",cnt);
      for(j=0;j<cnt;j++)
       printf(" %d",rec[j]);
      printf("/n");
     }
    }
  7. int main()
    {

     while(scanf("%d",&n)==1)
     {
      init();
      int i,j;
      int a,b,c;
      for(i=1;i<=n;i++)
      {
       scanf("%d",&a);
       while(a--)
       {
        scanf("%d",&b);
        addege(i,b+n);
       }
      }
      for(i=1;i<=n;i++)
      {
       scanf("%d",&b);
       addege(b+n,i);
      }
      tarjan();
      solve();
     }
     return 0;
    }
原创粉丝点击