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("\n");

193         putchar('\n');

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:\n",cas);

206         solve();

207     }

208     return 0;

209 }
View Code

 

你可能感兴趣的:(HDU)