这题跟POJ的1904很像。
大意就是
有n个王子和m个公主
每个王子都会喜欢若干个公主,也就是王子只跟自己喜欢的公主结婚
公主就比较悲惨, 跟谁结婚都行
然后输出王子可能的结婚对象
必须保证王子与任意这些对象中的一个结婚,都不会影响到剩余的王子的配对数,也就是不能让剩余的王子中突然有一个人没婚可结了
然后思路其实跟POJ1904非常像。
但是POJ那题给出了初始的一个完备匹配。
而本题没有
怎么办呢
我们就要想方设法构造出完备匹配
刚开始的时候我们可以先做一遍二分图最大匹配
那么因为两边人数不一等相等,所以可能有人会单身
那么这时候我们就要给这些单身的人安排对象了。
安排的对象不能是已有的这些人中的任何一个,那就只好再虚拟一些人出来了。
这些人比较杯具啊,对象都是虚拟的。
假设王子有剩下的,那么每个剩下的王子就连一个虚拟的公主,这个公主被所有的王子都喜欢。
假设公主有剩下的,那么每个剩下的公主就连一个虚拟的王子,这个王子喜欢所有的公主
然后就构造成完备匹配了。在下面的步骤就跟1904一摸一样了
上代码了 ,加了输入优化就比较爽。 如果有错误。请读者指出。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string>
#include <cstring>
#include <cmath>
#define MAXN 2005
#define INF 100000000
#define eps 1e-7
using namespace std;
struct Edge
{
int v, next;
}edge[200 * MAXN], newedge[255555];
int head[MAXN], e, visited[MAXN], newhead[MAXN], newe;
int top, scc, index;
int low[MAXN], dfn[MAXN], instack[MAXN];
int order[MAXN], cnt, st[MAXN], fa[MAXN];
int mark[MAXN], cx[MAXN], cy[MAXN];
int n, m;
int nt, all;
void init()
{
top = scc = index = e = 0;
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(instack, 0, sizeof(instack));
memset(newhead, -1, sizeof(newhead));
newe = 0;
}
inline void insert(const int &x, const int &y)
{
edge[e].v = y;
edge[e].next = head[x];
head[x] = e++;
}
inline int in()
{
char ch;
int a = 0;
while((ch = getchar()) == ' ' || ch == '\n');
a += ch - '0';
while((ch = getchar()) != ' ' && ch != '\n')
{
a *= 10;
a += ch - '0';
}
return a;
}
inline void out(int a)
{
if(a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
inline void newinsert(const int &x, const int &y)
{
newedge[newe].v = y;
newedge[newe].next = newhead[x];
newhead[x] = newe++;
}
inline int path(int u)
{
for(int i = newhead[u]; i != -1; i = newedge[i].next)
{
int v = newedge[i].v;
if(!mark[v])
{
mark[v] = 1;
if(cy[v] == -1 || path(cy[v]))
{
cx[u] = v;
cy[v] = u;
return 1;
}
}
}
return 0;
}
int solve()
{
int ans = 0;
memset(cx, -1, sizeof(cx));
memset(cy, -1, sizeof(cy));
for(int i = 1; i <= nt; i++)
{
memset(mark, 0, sizeof(mark));
ans += path(i);
}
return ans;
}
void readdata()
{
int t, v;
for(int i = 1; i <= n; i++)
{
t = in();
while(t--)
{
v = in();
insert(i, v + nt);
newinsert(i, v + nt);
}
}
solve();
all = 2 * nt;
for(int i = 1; i <= nt; i++)
if(cx[i] == -1)
{
++all;
cx[i] = all;
cy[all] = i;
for(int k = 1; k <= nt; k++)
insert(k, all);
}
for(int j = 1; j <= nt; j++)
if(cy[j + nt] == -1)
{
++all;
cy[j + nt] = all;
cx[all] = j + nt;
for(int k = 1; k <= nt; k++)
insert(all, k + nt);
}
for(int i = 1; i <= all; i++)
if(cx[i] != -1)
insert(cx[i], i);
}
void tarjan(int u)
{
low[u] = dfn[u] = ++index;
instack[u] = 1;
st[++top] = u;
int v;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u])
{
scc++;
do
{
v = st[top--];
instack[v] = 0;
fa[v] = scc;
}while(v != u);
}
}
void gao()
{
init();
readdata();
for(int i = 1; i <= all; i++)
if(!dfn[i]) tarjan(i);
for(int u = 1; u <= n; u++)
{
cnt = 0;
int ans[MAXN];
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(fa[u] == fa[v])
{
if(v - nt <= m)
ans[cnt++] = v - nt;
}
}
sort(ans, ans + cnt);
out(cnt);
for(int i = 0; i < cnt; i++)
{
putchar(' ');
out(ans[i]);
}
puts("");
}
}
int main()
{
int cas = 0;
int T;
//freopen("C:/in.txt", "r", stdin);
//freopen("C:/out2.txt", "w", stdout);
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
nt = max(n, m);
printf("Case #%d:\n", ++cas);
gao();
}
return 0;
}