题目链接:uva 1444 - Knowledge for the masses
题目大意:给出R和L,R表示有R行,L表示一行的最大长度。
对于每一行,给出n,然后是n个数,arr[i]为0表示空格,长度为1,否则表示书架,长度为arr[i]。现在人要从上边走到下边,问说最少移动几个书架,并且输出可以通过的路径坐标。
解题思路:c[i]表示第i个坐标有多少行可以通过,当c[i]==R时,表示人可以从该位置穿过整个书架。g[i]表示从i这个位置穿过的代价。然后对于每一行处理,pos[i]记录第i个空格的位置,vis[i]记录左移的代价,用来和右移代价作比较,取最小值。注意第二行输出的时候每个数后面都要根空格,否则PE。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e6+5;
const int INF = 0x3f3f3f3f;
int R, L, c[maxn], g[maxn];
int n, arr[maxn], pos[maxn], vis[maxn];
void input () {
scanf("%d", &n);
memset(vis, -1, sizeof(vis));
int cnt = 0, mv = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
if (arr[i] == 0) {
mv++;
pos[cnt++] = i;
c[mv-1]++;
} else {
int k = min(cnt, arr[i]);
mv = mv + arr[i];
for (int j = 1; j <= k; j++) {
int u = mv - j;
vis[u] = i - pos[cnt-j] - j + 1;
g[u] += vis[u];
c[u]++;
}
}
}
reverse(arr, arr+n);
cnt = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == 0) {
mv--;
pos[cnt++] = i;
} else {
int k = min(cnt, arr[i]);
mv = mv - arr[i];
for (int j = 0; j < k; j++) {
int u = mv + j;
if (vis[u] == -1) {
vis[u] = i - pos[cnt-j-1] - j;
g[u] += vis[u];
c[u]++;
} else {
int tmp = i - pos[cnt-j-1] - j;
g[u] += min(0, tmp - vis[u]);
}
}
}
}
}
void init () {
scanf("%d%d", &R, &L);
memset(c, 0, sizeof(c));
memset(g, 0, sizeof(g));
for (int i = 0; i < R; i++)
input();
}
void solve () {
int ans = INF, cnt = 0;
for (int i = 0; i < L; i++) {
if (c[i] == R) {
if (g[i] < ans) {
cnt = 0;
ans = g[i];
}
if (g[i] == ans)
vis[cnt++] = i;
}
}
/*
printf("%d\n%d", ans, vis[0]);
for (int i = 1; i < cnt; i++)
printf(" %d", vis[i]);
printf("\n");
*/
printf("%d\n", ans);
for (int i = 0; i < cnt; i++)
printf("%d ", vis[i]);
printf("\n");
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
init();
solve();
}
return 0;
}
时间: 2024-10-09 23:09:36