hdu 4685 Prince and Princess(二分匹配+强连通)

这题最开始我是输入n跟m,然后就加入虚拟节点使二分图左右两边节点数一样。。。wa了几发后才知道,加入虚拟节点是根据原图的二分匹配结果M决定的,左边还有x-M个没匹配,右边还有y-M个没匹配,所以这时应加入虚拟节点,使两边节点数均为x+y-M,这样才能保证那些原先没有匹配到的王子跟公主也在连通图中。比如两个王子,一个公主,这样的正解应该是两个王子都能娶该公主的。加入的新王子,每个公主都喜欢;加入的新公主,每个王子都喜欢。。好凶残。。然后依次给左右两边未能配对的手动配对(不用再做二分匹配了),左边节点为公主节点,右边为王子。对于u王子,从他配对的v公主,向所有u喜欢却没能配上对的公主节点连边。对这样的一个图求scc,如果两个公主节点再同一个连通分量里面,则说明匹配到这两个公主的两个王子是可以互换公主且不会影响最大匹配对的。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<fstream>
#include<sstream>
#include<bitset>
#include<vector>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define FF(i, a, b) for(int i=a; i<b; i++)
#define FD(i, a, b) for(int i=a; i>=b; i--)
#define REP(i, n) for(int i=0; i<n; i++)
#define CLR(a, b) memset(a, b, sizeof(a))
#define debug puts("**debug**")
#define LL long long
#define PB push_back
#define MP make_pair
using namespace std;

const int maxn = 1000;
int T, n, m, g[maxn][maxn], match[maxn];
int uN, vN;
bool vis[maxn], use[maxn];

bool dfs(int u)
{
    FF(i, 1, vN+1) if(!vis[i] && g[u][i])
    {
        vis[i] = true;
        if(match[i] == 0 || dfs(match[i]))
        {
            match[i] = u;
            return true;
        }
    }
    return false;
}

int hungary()
{
    int ret = 0;
    CLR(match, 0);
    FF(i, 1, uN+1)
    {
        CLR(vis, 0);
        if(dfs(i)) ret++;
    }
    return ret;
}

int pre[maxn], low[maxn], dfs_clock, scc_cnt, sccno[maxn];
vector<int> G[maxn];
stack<int> S;

void dfs1(int u)
{
    pre[u] = low[u] = ++dfs_clock;
    S.push(u);
    REP(i, G[u].size())
    {
        int v = G[u][i];
        if(!pre[v])
        {
            dfs1(v);
            low[u] = min(low[u], low[v]);
        }
        else if(!sccno[v]) low[u] = min(low[u], pre[v]);
    }
    if(low[u] == pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x = S.top(); S.pop();
            sccno[x] = scc_cnt;
            if(x == u) break;
        }
    }
}

void find_scc(int n)
{
    dfs_clock = scc_cnt = 0;
    CLR(pre, 0); CLR(sccno, 0);
    FF(i, 1, n+1) if(!pre[i]) dfs1(i);
}

void build()
{
    uN = m, vN = n;
    int M = hungary();
    uN = n+m-M, vN = m+n-M;
    FF(i, m+1, uN+1) FF(j, 1, vN+1) g[i][j] = 1;
    FF(i, n+1, vN+1) FF(j, 1, uN+1) g[j][i] = 1;

    CLR(use, 0);
    int x = m+1;
    FF(i, 1, n+1)
    {
        if(match[i] == 0) match[i] = x++;
        else use[match[i]] = 1;
    }
    x = n+1;
    FF(i, 1, m+1) if(!use[i]) match[x++] = i;
}

void solve(int N)
{
    REP(i, N+1) G[i].clear();
    FF(i, 1, N+1) FF(j, 1, N+1)
        if(g[j][i] && j != match[i]) G[match[i]].PB(j);

    find_scc(N);

    vector<int> ans;
    FF(i, 1, n+1)
    {
        ans.clear();
        FF(j, 1, m+1) if(g[j][i] && sccno[j] == sccno[match[i]])
        ans.PB(j);

        int nc = ans.size();
        printf("%d", nc);
        REP(j, nc) printf(" %d", ans[j]);
        puts("");
    }
}

int main()
{
    scanf("%d", &T);
    FF(kase, 1, T+1)
    {
        scanf("%d%d", &n, &m);
        CLR(g, 0);
        int x, y;
        FF(i, 1, n+1)
        {
            scanf("%d", &x);
            while(x--)
            {
                scanf("%d", &y);
                g[y][i] = 1;
            }
        }

        build();

        printf("Case #%d:\n", kase);
        solve(uN);
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值