选数字
2.1 题目描述Description
jn 在你的帮助下完成数学作业后, 又向你提出了一个苦思冥想但仍然不会做的问题。 给出一
个长度为 3n 的数列,规定相邻的 n 个数只能选 k 个,最大化所选数的和
2.2 输入Input
从 num.in 输入第一行有两个正整数 n,k,第二行有 3n 个正整数,即
i
a
2.3 输出Output
输出到 num.out,输出为最大的满足条件的数字之和
2.4 样例输入SampleInput
5 3
14 21 9 30 11 8 1 20 29 23 17 27 7 8 35
2.5 样例输出SampleOutput
195
2.6 数据范围Hint
对于 20%的数据,n≤20
对于 60%的数据,n≤40
对于 20%的数据,k=1
对于 20%的数据,a[i] ≤100
2.1 题目描述Description
jn 在你的帮助下完成数学作业后, 又向你提出了一个苦思冥想但仍然不会做的问题。 给出一
个长度为 3n 的数列,规定相邻的 n 个数只能选 k 个,最大化所选数的和
2.2 输入Input
从 num.in 输入第一行有两个正整数 n,k,第二行有 3n 个正整数,即
i
a
2.3 输出Output
输出到 num.out,输出为最大的满足条件的数字之和
2.4 样例输入SampleInput
5 3
14 21 9 30 11 8 1 20 29 23 17 27 7 8 35
2.5 样例输出SampleOutput
195
2.6 数据范围Hint
对于 20%的数据,n≤20
对于 60%的数据,n≤40
对于 20%的数据,k=1
对于 20%的数据,a[i] ≤100
对于 100%的数据,n≤200,k≤10,0≤a[i]<=10^6以上数据有交集
题解:这道题我写的最大费用最大流。刚开始是按照k==1的情况思考的,想拿些部分分,结果A了。
先说怎么见图吧。
首先拆点,拆成的两个点之间连一条容量为1,价值为a[i]的边。然后从源点向每个点连一条容量为1,价值为0的边,
从每个点向汇点连一条容量为1,价值为0的边。因为相邻的n各点只能取k个,那么我们强制所选的每一条路径上的点都是属于不同的快,即两点之间的距离至少为n,就是从i点向i+n和之后的点连边,容量为1,价值为0。最后,把汇点拆开,连边容量为K,价值为0. 这样我们就会最多选择K条路径,而路径上的点都分属不同的快,这样的话每个快最多选取K个点,即保证了正确性。如果还是不懂的话,就只能感性的理解一下了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,k,a[1000],maxn,dis[100000],laste[100000],can[100000];
int next[2000000],point[100000],v[2000000],remain[2000000],cost[2000000],tot=-1;
int const inf=1e9;
void add(int x,int y,int z,int k)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z; cost[tot]=k;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; cost[tot]=-k;
}
int addflow(int s,int t)
{
int ans=inf,now=t;
while (now!=s)
{
ans=min(ans,remain[laste[now]]);
now=v[laste[now]^1];
}
now=t;
while (now!=s)
{
remain[laste[now]]-=ans;
remain[laste[now]^1]+=ans;
now=v[laste[now]^1];
}
return ans;
}
bool spfa(int s,int t)
{
memset(dis,128,sizeof(dis));
memset(can,0,sizeof(can));
can[s]=1;
queue<int> p; p.push(s); dis[s]=0;
while (!p.empty())
{
int now=p.front(); p.pop(); can[now]=0;
for (int i=point[now];i!=-1;i=next[i])
if (dis[v[i]]<dis[now]+cost[i]&&remain[i])
{
dis[v[i]]=dis[now]+cost[i];
laste[v[i]]=i;
if (!can[v[i]])
{
can[v[i]]=1;
p.push(v[i]);
}
}
}
if (dis[t]<0) return 0;
maxn+=addflow(s,t)*dis[t];
return 1;
}
void maxflow(int s,int t)
{
while (spfa(s,t));
}
int main()
{
freopen("num.in","r",stdin);
freopen("num.out","w",stdout);
memset(next,-1,sizeof(next));
memset(point,-1,sizeof(point));
scanf("%d%d",&n,&k);
for (int i=1;i<=3*n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=3*n;i++)
add(0,i,1,0);
for (int i=1;i<=3*n;i++)
add(i+3*n,6*n+1,1,0);
for (int i=1;i<=3*n;i++)
{
add(i,i+3*n,1,a[i]);
for (int j=i+n;j<=3*n;j++)
add(i+3*n,j,1,0);
}
add(6*n+1,6*n+2,k,0);
maxflow(0,6*n+2);
printf("%d",maxn);
}