问题
- 给定偶数个数
a
[
1
]
、
a
[
2
]
、
.
.
.
、
a
[
n
]
a[1]、a[2]、...、a[n]
a[1]、a[2]、...、a[n]。
- 分别输出从这n个数里选
1
、
2
、
3
、
…
、
n
/
2
1、2、3、…、n/2
1、2、3、…、n/2 个数时的和的最大值,选数规则是不能同时选相邻的数。
-
1
≤
a
[
i
]
≤
1000
,
2
≤
n
≤
100000
1\leq a[i] \leq 1000,2 \leq n \leq 100000
1≤a[i]≤1000,2≤n≤100000
- 输入:
1
10
737 757 860 778 371 591 20 241 768 442 - 输出
860
1628
2365
2956
2871
分析
- 顶点数1e5,使用费用流则超时
- 当第2个数选择768后,在x+768 >= 241+442无法满足时,将会选择768前后的241和442两个数,且放弃768(反悔操作)
- 当选择了737后,就不可能再放弃737(无对应的反悔操作)
- 网络流(可将in和out之间的数字顶点删除,数字成为in和out两顶点间路径的费用系数)
代码
优先队列
#include<bits/stdc++.h>
using namespace std;
const int MXN = 100010, inf = 0x3f3f3f3f;
struct Range{
int l, pre, nxt, v;
bool operator<(Range x)const{ return v < x.v;}
}r[MXN];
priority_queue<Range> q;
int main(){
int t, n, ans, cnt;
scanf("%d", &t);
while(t--){
ans = 0;
while(!q.empty()) q.pop();
scanf("%d", &n);
for(int i = 1; i <= n; ++i){
scanf("%d", &r[i].v);
r[i].pre = i-1, r[i].nxt = i+1;
q.push((Range){i, 0, 0, r[i].v});
}
cnt = n/2;
while(!q.empty() && cnt){
Range k = q.top();
q.pop();
Range &y = r[k.l];
if(y.v != k.v) continue;
ans += y.v, cnt--;
printf("%d\n", ans);
Range &x = r[y.pre], &z = r[y.nxt];
if(y.pre < 1 && y.nxt > n) continue;
else if(y.pre == 0) y.v = z.v = -inf, r[z.nxt].pre = 0;
else if(y.nxt > n) x.v =y.v = -inf, r[x.pre].nxt = y.nxt;
else{
x.v += z.v - y.v, x.nxt = z.nxt;
y.v = z.v = -inf;
r[z.nxt].pre = y.pre;
k.v = x.v, k.l = y.pre;
q.push(k);
}
}
}
return 0;
}
最大费用最大流【TLE】
#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f, MXN = 100010, MX = 1000;
int d[MXN<<1], pre[MXN<<1], flow[MXN<<1], v[MXN<<1];
int tot, head[MXN<<1];
struct Edge{int to, nxt, w, c;}edge[MXN<<3];
void addEdge(int u, int v, int w, int c){
Edge &e = edge[++tot];
e.to = v, e.nxt = head[u], e.w = w, e.c = c, head[u] = tot;
}
void add(int u, int v, int w, int c){
addEdge(u, v, w, c), addEdge(v, u, 0, -c);
}
void spfa(int s, int t){
queue<int> q;
int f;
memset(d, 0xcf, sizeof d), memset(v, 0, sizeof v);
v[s] = 1, d[s] = 0, flow[s] = inf, q.push(s);
while(!q.empty()){
f = q.front(), q.pop(), v[f] = 0;
for(int to, i = head[f]; ~i; i = edge[i].nxt){
if(!edge[i].w) continue;
to = edge[i].to;
if(d[to] < d[f] + edge[i].c){
d[to] = d[f] + edge[i].c;
flow[to] = min(flow[f], edge[i].w);
pre[to] = i;
if(!v[to]) v[to] = 1, q.push(to);
}
}
}
}
void update(int s, int t){
for(int i, now = t; now != s; now = edge[i^1].to)
i = pre[now], edge[i].w -= flow[t], edge[i^1].w += flow[t];
}
int main(){
int t, a, maxflow, ans, n, k, S, T;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
k = n/2, S = n+2, T = n+3, tot = 1, ans = 0, maxflow = 0;
memset(head, -1, sizeof head);
for(int i = 1; i <= k; ++i)
scanf("%d", &a), add(i, k+i, 1, a), scanf("%d", &a), add(i, k+i+1, 1, a);
for(int i = 1; i <= k; ++i) add(S, i, 1, 0);
for(int i = k+1; i <= n+1; ++i) add(i, T, 1, 0);
for(int i = 1; i <= k; ++i){
spfa(S, T), maxflow += flow[T], ans += flow[T]*d[T], update(S, T);
printf("%d\n", ans);
}
}
return 0;
}