链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44750187");
}
题解:
我依然只会做,不会证。
如果初学者,可以一览,想深究,请移步。
After all,i am a Juruo at present.
首先我们可以有基础的线性规划:每连续n点最多选k个。
转换成数学模型:
(其中 a 数组表示选(1)与不选(0),而 t 数组则是辅助变量,将小于等于关系转化为等于关系)
(至于为什么我不用use啊,choose啊什么的作为变量名——你们看一眼它们在公式中变成啥样就知道了——use、choose)
(∑ni=1ai)+t1=k
?
(∑3ni=2n+1ai)+t2n+1=k
然后我们差分一下这2n+1个式子,保留第一个和最后一个式子,会得到:
k=(∑ni=1ai)+t1
a1+t1=an+1+t2
a2+t2=an+2+t3
?
a2n+t2n=a3n+t2n+1
(∑3ni=2n+1ai)+t2n+1=k
然后关键的时刻到了!我们把每个式子看作一个节点,而边则是式子之间的关系。
那么对于此题我们目前就拥有了3n个项为常数的式子节点,和2个项为O(n)的式子节点。(当然还需要两个节点作为超级源和超级汇来控制流量)
点已经明了了,那么边呢?
前面说过边是式子间的关系,而我们不妨把每个等号看作那个节点的本质,那么等号的左边就是节点的入边总容量,而等号的右边就是节点的出边总容量。
然后我们分析每个变量的含义以及定义域,由此来确定每条边(节点之间关系)的费用以及容量。这个应该很显然, a 是取或不取,那么它的容量应该就是简单的 1 费用则是它本身的取值 vali,而 f 是一个辅助变量,显然容量就应该是 inf ,而费用则是 0 。但是因为题目中的限定“k”,所以我们可以将这个容量设为“inf”
图建完了,我们还需要超级源点连源点,容量k,费用0,汇点连超级汇点,容量k,费用0来进行总的限制。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 610
#define M 5000
#define inf 0x3f3f3f3f
using namespace std;
struct Eli
{
int u,v,len,fee,next;
}e[M];
int head[N],cnt;
inline void add(int u,int v,int len,int fee)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].len=len;
e[cnt].fee=fee;
e[cnt].next=head[u];
head[u]=cnt;
}
inline void ADD(int u,int v,int len,int fee)
{add(u,v,len,-fee),add(v,u,0,fee);}
int dist[N],s,t;
int lim[N],pre[N];
bool in[N];
queue<int>q;
void spfa()
{
while(!q.empty())q.pop();
memset(dist,0x3f,sizeof dist);
q.push(s),dist[s]=0,lim[s]=inf;
int i,u,v;
while(!q.empty())
{
u=q.front(),q.pop(),in[u]=0;
for(i=head[u];i;i=e[i].next)if(e[i].len)
{
if(dist[v=e[i].v]>dist[u]+e[i].fee)
{
dist[v]=dist[u]+e[i].fee;
lim[v]=min(e[i].len,lim[u]);
pre[v]=i;
if(!in[v])q.push(v),in[v]=1;
}
}
}
return ;
}
void handle(int flow)
{
for(int i=pre[t];i;i=pre[e[i].u])
{
e[i].len-=flow;
e[i^1].len+=flow;
}
}
int minfee,n,m,p,S,T;
int val[N];
bool build()
{
int i,j,k;
int x,y;
scanf("%d%d",&n,&m);
S=0,T=n*2+1,cnt=1,s=n*2+2,t=n*2+3;
ADD(s,S,m,0),ADD(T,t,m,0);
for(i=1;i<=n*3;i++)scanf("%d",&val[i]);
for(i=1;i<=n;i++)
{
ADD(S,i,1,val[i]);
ADD(i,i+n,1,val[i+n]);
ADD(i+n,T,1,val[i+(n<<1)]);
}
for(i=1;i<=T;i++)ADD(i-1,i,m,0);
return 0;
}
int main()
{
freopen("test.in","r",stdin);
build();
while(spfa(),dist[t]<inf)
{
minfee+=lim[t]*dist[t];
handle(lim[t]);
}
cout<<(-minfee)<<endl;
return 0;
}