Bzoj 3661: Hungry Rabbit

传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=3661
题解:
解法一:网络流
  按天建分层图,两天之间一只兔子如果都可以出行,就直接连向下一天,所有上一天能出行的兔子连到一个转换点,转换点再连向下一天能出行的兔子,转换点要拆点,限制流量为 l ,一个兔子不可以即走转换点又直接走向下一天,所以兔子也拆点限制一下流量为 1 即可。总流量 k 只要将源点拆点限制流量为 k 即可。复杂度 O( 能过 ) 54881ms
解法二:贪心
  对于每一天贪心地找后一段能持续走最长天数的兔子,两天之间将前一天出来的和没出来的兔子分别排序,用前一天没出来的将来能走天数前 l 长的兔子更新前一天出来的将来能走天数前 l 短的兔子。(正确性我也不会证QAQ)复杂度 O(mnlogn) 592ms

网络流:

#include<bits/stdc++.h>
const int N = 805;
const int M = 805;
const int Node = N * M * 3;
const int Edge = Node * 3 * 2;
const int INF = 1e9;
struct edge {
    int y, v, next;
}mp[Edge];
int n, m, k, l, S, T, first[Node], cur[Node], s, h[Node], q[Node], match;
char ch[N][M];
void ins(int x, int y, int v) {
    //printf("x=%d y=%d v=%d\n", x, y, v);
    mp[++s] = (edge){y, v, first[x]}; first[x] = s;
    mp[++s] = (edge){x, 0, first[y]}; first[y] = s;
};
void build() {
    int t = n * m * 2; s = 1;
    for (int j = 0; j < m - 1; j++) {
        for (int i = 0; i < n; i++)
            if (ch[i][j] == '1') {
                ins((j * n + i) * 2, (j * n + i) * 2 + 1, 1);
                ins((j * n + i) * 2 + 1, t + j * 2, 1);
                if (ch[i][j + 1] == '1')
                    ins((j * n + i) * 2 + 1, ((j + 1) * n + i) * 2, 1);
            }
        for (int i = 0; i < n; i++)
            if (ch[i][j + 1] == '1')
                ins(t + j * 2 + 1, ((j + 1) * n + i) * 2, 1);
        ins(t + j * 2, t + j * 2 + 1, l);
    }
    for (int i = 0; i < n; i++)
        if (ch[i][m - 1] == '1')
            ins(((m - 1) * n + i) * 2, ((m - 1) * n + i) * 2 + 1, 1);
    t += m * 2;
    S = t + 1, T = t + 2;
    ins(S, t, k);
    for (int i = 0; i < n; i++)
        if (ch[i][0]) ins(t, i * 2, 1);
    for (int i = 0; i < n; i++)
        if (ch[i][m - 1]) ins(((m - 1) * n + i) * 2 + 1, T, 1);
}
bool bfs() {
    memset(h, 0, sizeof(h));
    for (int i = 0; i <= T; i++)
        cur[i] = first[i];
    int head = 1, tail = 1;
    h[q[head] = S] = 1;
    for (int x = q[head]; head <= tail; x = q[++head])
        for (int t = first[x]; t; t = mp[t].next)
            if (mp[t].v && !h[mp[t].y]) {
                h[mp[t].y] = h[x] + 1,
                q[++tail] = mp[t].y;
                if (mp[t].y == T) return 1;
            }
    return 0;
}
int dfs(int x, int f) {
    if (x == T) return f;
    int used = 0, b;
    for (int t = cur[x]; t; t = cur[x] = mp[t].next)
        if (h[x] + 1 == h[mp[t].y]) {
            b = dfs(mp[t].y, std::min(f - used, mp[t].v));
            mp[t].v -= b;
            mp[t ^ 1].v += b;
            used += b;
            if (used == f) return used;
        }
    h[x] = -1;
    return used;
}
int main() {
    scanf("%d%d%d%d", &n, &m, &k, &l);
    for (int i = 0; i < n; i++) scanf("%s", ch[i]);
    build();
    while (bfs()) match += dfs(S, INF);
    if (match < k) {printf("-1\n"); return 0;}
    for (int j = 0; j < m; j++) {
        for (int i = 0; i < n; i++)
            for (int t = first[(j * n + i) * 2]; t; t = mp[t].next)
                if (mp[t].y == (j * n + i) * 2 + 1 && !mp[t].v)
                    printf("%d ", i + 1);
        printf("\n");
    }
    return 0;
}

贪心:

#include<bits/stdc++.h>
const int N = 805;
struct rec {
    int num, d;
    rec() {}
    rec(int _num, int _d):
        num(_num), d(_d) {}
} a[N], b[N];
bool cmp1(const rec &a, const rec &b) {return a.d > b.d;}
bool cmp2(const rec &a, const rec &b) {return a.d < b.d;}
int n, m, k, l, d[N][N], p[N][N], cnt1, cnt2;
bool picked[N];
char ch[N];
int main() {
    scanf("%d%d%d%d", &n, &m, &k, &l);
    for (int i = 1; i <= n; i++) {
        scanf("%s", ch + 1);
        for (int j = m; j > 0; j--)
            if (ch[j] == '0')
                d[i][j] = 0;
            else
                d[i][j] = d[i][j + 1] + 1;
    }
    for (int i = 1; i <= n; i++)
        if (d[i][1]) a[++cnt1] = rec(i, d[i][1]);
    std::sort(a + 1, a + cnt1 + 1, cmp1);
    if (cnt1 < k) {printf("-1\n"); return 0;}
    for (int i = 1; i <= k; i++)
        p[1][i] = a[i].num,
        picked[a[i].num] = 1;
    for (int i = 2; i <= m; i++) {
        cnt1 = cnt2 = 0;
        for (int j = 1; j <= k; j++)
            b[++cnt2] = rec(p[i - 1][j], d[p[i - 1][j]][i]);
        for (int j = 1; j <= n; j++)
            if (!picked[j]) a[++cnt1] = rec(j, d[j][i]);
        std::sort(a + 1, a + cnt1 + 1, cmp1);
        std::sort(b + 1, b + cnt2 + 1, cmp2);
        for (int j = 1; j <= k; j++) {
            if (j <= l && a[j].d > b[j].d)
                picked[a[j].num] = 1,
                picked[b[j].num] = 0,
                std::swap(a[j], b[j]);
            p[i][j] = b[j].num;
            if (!b[j].d) {printf("-1\n"); return 0;}
        }
    }
    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= k; j++)
            printf("%d ", p[i][j]);
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值