校内互测 选数字

选数字
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
#include
#include
#include
#include
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 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]]


你可能感兴趣的:(网络流)