傳送門: http://www.lydsy.com/JudgeOnline/problem.php?id=3661
題解:
解法一:網絡流
按天建分層圖,兩天之間一隻兔子如果都可以出行,就直接連向下一天,所有上一天能出行的兔子連到一個轉換點,轉換點再連向下一天能出行的兔子,轉換點要拆點,限制流量爲
解法二:貪心
對於每一天貪心地找後一段能持續走最長天數的兔子,兩天之間將前一天出來的和沒出來的兔子分別排序,用前一天沒出來的將來能走天數前
網絡流:
#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;
}