bzoj1433_最大流|二分图最大匹配

10 篇文章 0 订阅
2 篇文章 0 订阅

调了一下午的网络流, 最后发现是因为想要用0作为下标而遍历的时候还是用习惯性的写法, 简直不开心。

网络流的题目基本都是重点在建模上, 我们来看看这一题怎么建模: 首先, 学生人数和可用床数是确定的, 我们就自己创造一个源点和一个汇点。 考虑到学生必须全部有床睡, 那么从原点出发流到床再流到学生即可。 这时我们能够机智的发现一件事, 其实就是求一个二分图的最大匹配, 愤愤然地感觉自己被坑了。 最终只要看匹配数是否等于有需求的学生数即可。

另一件事就是判断有需求的学生, 只要是外来的或校内但不回家的就是有需求的。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdlib>
#define N 200
#define M 20000
#define INF 10000000

using namespace std;

struct edge
{
    int to, next;
}e[M];
int t, n, num, ans, cont;
int a[N], b[N], p[N], mat[N], flag[N];
void add(int x, int y)
{
    e[num].to = y;
    e[num].next = p[x];
    p[x] = num++;
}
void clean()
{
    ans = num = cont = 0;
    memset(p, -1, sizeof p);
    memset(e, 0, sizeof e);
    memset(mat, 0, sizeof mat);
}
void init()
{
    clean();
    int x;
    scanf("%d", &n);
    t = n << 1 | 1;
    for (int i = 1; i <= n; ++i)
    scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
    scanf("%d", &b[i]);
    for (int i = 1; i <= n; ++i)
    if (!a[i] || (a[i] && !b[i])) ++cont;
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j)
    {
        scanf("%d", &x);
        if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i])))
        {
            add(j+n, i);
            add(i, j+n);
        }
    }
}
bool find(int x)
{
    for (int i = p[x]; i != -1; i = e[i].next)
    {
        int k = e[i].to;
        if (!flag[k])
        {
            flag[k] = 1;
            if (!mat[k] || find(mat[k]))
            {
                mat[k] = x;
                return true;
            }
        }
    }
    return false;
}
void deal()
{
    for (int i = 1; i <= n; ++i)
    {
        memset(flag, 0, sizeof flag);
        ans += find(i);
    }
    if (ans == cont) printf("^_^\n");
    else printf("T_T\n");
}
int main()
{
    freopen("a.in", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--)
    {
        init();
        deal();
    }
    return 0;
}//二分图匹配代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cstdlib>
#define N 200
#define M 20000
#define INF 10000000

using namespace std;

struct edge
{
    int to, next, cap, flow;
}e[M];
int t, n, num, ans, cont;
int a[N], b[N], p[N], d[N], flag[N], now[N];
void add(int x, int y, int z)
{
    e[num].to = y;
    e[num].next = p[x];
    e[num].cap = z;
    p[x] = num++;
}
void clean()
{
    ans = num = cont = 0;
    memset(p, -1, sizeof p);
    memset(d, 0, sizeof d);
    memset(e, 0, sizeof e);
}
void init()
{
    clean();
    int x;
    scanf("%d", &n);
    t = n << 1 | 1;
    for (int i = 1; i <= n; ++i)
    scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i)
    scanf("%d", &b[i]);
    for (int i = 1; i <= n; ++i)
    if (!a[i] || (a[i] && !b[i]))
    {
        add(i, t, 1);
        add(t, i, 0);
        ++cont;
    }
    for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= n; ++j)
    {
        scanf("%d", &x);
        if (((i == j && a[i]) || (x && a[j])) && (!a[i] || (a[i] && !b[i])))
        {
            add(j+n, i, 1);
            add(i, j+n, 0);
        }
    }
    for (int i = 1; i <= n; ++i)
    if (a[i])
    {
        add(0, i+n, 1);
        add(i+n, 0, 0);
    }
}
bool bfs()
{
    memset(flag, 0, sizeof flag);
    d[0] = 0, flag[0] = 1;
    queue<int>q;
    q.push(0);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for (int i = p[x]; i != -1; i = e[i].next)
        {
            int k = e[i].to;
            if (!flag[k] && e[i].cap > e[i].flow)
            {
                flag[k] = 1;
                d[k] = d[x] + 1;
                q.push(k);
            }
        }
    }
    for (int i = 0; i <= t; ++i) now[i] = p[i];
    return flag[t];
}
int dfs(int x, int mini)
{
    if (x == t || !mini) return mini;
    int flow = 0;
    for (int i = now[x]; i != -1; i = e[i].next)
    {
        now[x] = i;
        int k = e[i].to;
        if (d[k] == d[x] + 1)
        {
            int tmp = dfs(k, min(mini, e[i].cap-e[i].flow));
            if (tmp <= 0) continue;
            e[i].flow += tmp;
            e[i^1].flow -= tmp;
            flow += tmp;
            mini -= tmp;
            if (!mini) break;
        }
    }
    return flow;
}
void deal()
{
    while(bfs()) ans += dfs(0, INF);
    if (ans == cont) printf("^_^\n");
    else printf("T_T\n");
}
int main()
{
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
    int T;
    scanf("%d", &T);
    while(T--)
    {
        init();
        deal();
    }
    return 0;
}//网络流代码



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值