学姐的逛街计划
描述
doc
d
o
c
最近太忙了, 每天都有课. 这不怕,
doc
d
o
c
可以请假不去上课.
偏偏学校又有规定, 任意连续
n
n
天中, 不得请假超过 天.
doc
d
o
c
很忧伤, 因为他还要陪学姐去逛街呢.
后来,
doc
d
o
c
发现, 如果自己哪一天智商更高一些, 陪学姐逛街会得到更多的好感度.
现在
doc
d
o
c
决定做一个实验来验证自己的猜想, 他拜托 小岛 预测出了 自己 未来
3n
3
n
天中, 每一天的智商.
doc
d
o
c
希望在之后的
3n
3
n
天中选出一些日子来陪学姐逛街, 要求在不违反校规的情况下, 陪学姐逛街的日子自己智商的总和最大.
可是, 究竟这个和最大能是多少呢?
输入格式
第一行给出两个整数,
n
n
和, 表示我们需要设计之后
3n
3
n
天的逛街计划, 且任意连续
n
n
天中不能请假超过 天.
第二行给出
3n
3
n
个整数, 依次表示
doc
d
o
c
每一天的智商有多少. 所有数据均为64位无符号整数
输出格式
输出只有一个整数, 表示可以取到的最大智商和.
样例输入1
5 3
14 21 9 30 11 8 1 20 29 23 17 27 7 8 35
样例输出1
195
限制
对于 20% 的数据,
1<=n<=12,k=3.
1
<=
n
<=
12
,
k
=
3.
对于 70% 的数据,
1<=n<=40.
1
<=
n
<=
40
.
对于 100% 的数据,
1<=n<=200,1<=k<=10.
1
<=
n
<=
200
,
1
<=
k
<=
10.
解:
网络流的一个套路:用流量平衡表达等式。
用取值0或1表示第
i
i
天是否逛街。
建立不等式:
…
di+di+1+di+2+...+di+n−1≤k
d
i
+
d
i
+
1
+
d
i
+
2
+
.
.
.
+
d
i
+
n
−
1
≤
k
…
d2n+1+d2n+2+d2n+3+...+d3n≤k
d
2
n
+
1
+
d
2
n
+
2
+
d
2
n
+
3
+
.
.
.
+
d
3
n
≤
k
增加调节变量(
yi
y
i
):
d1+d2+d3+...+dn+y1=k
d
1
+
d
2
+
d
3
+
.
.
.
+
d
n
+
y
1
=
k
…
di+di+1+di+2+...+di+n−1+yi=k
d
i
+
d
i
+
1
+
d
i
+
2
+
.
.
.
+
d
i
+
n
−
1
+
y
i
=
k
…
d2n+1+d2n+2+d2n+3+...+d3n+y2n+1=k
d
2
n
+
1
+
d
2
n
+
2
+
d
2
n
+
3
+
.
.
.
+
d
3
n
+
y
2
n
+
1
=
k
用上式减下式:
d1+y1=dn+1+y2
d
1
+
y
1
=
d
n
+
1
+
y
2
…
di+yi=dn+i+yi+1
d
i
+
y
i
=
d
n
+
i
+
y
i
+
1
…
d2n+y2n=d3n+y2n+1
d
2
n
+
y
2
n
=
d
3
n
+
y
2
n
+
1
由于有变量不足,我们增加两个等式:
k=d1+d2+d3+...+dn+y1
k
=
d
1
+
d
2
+
d
3
+
.
.
.
+
d
n
+
y
1
d2n+1+d2n+2+d2n+3+...+d3n+y2n+1=k
d
2
n
+
1
+
d
2
n
+
2
+
d
2
n
+
3
+
.
.
.
+
d
3
n
+
y
2
n
+
1
=
k
这样的话,每个变量出现两次,左右各一次。
我们把每个等式看成点,每个变量看作边,在左边连入流,右边连出流。最后两个变量连源点和汇点,流量为
k
k
。
跑费用流即可。
想一下有下界怎么做???
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
struct lxy{
int next,to,flow,cost;
}b[100005];
int head[1005],data[1005],cnt=-1;
int n,k,s,t,ans;
int dis[1005];
bool vis[1005];
queue <int> d;
void add(int op,int ed,int len,int w){
b[++cnt].next=head[op];
b[cnt].to=ed;
b[cnt].flow=len;
b[cnt].cost=w;
head[op]=cnt;
}
bool bfs(){
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[s]=0;d.push(s);
while(!d.empty()){
int now=d.front();d.pop();vis[now]=0;//cout<<now<<endl;
for(int i=head[now];i!=-1;i=b[i].next)
if(b[i].flow!=0&&dis[now]+b[i].cost<dis[b[i].to]){
dis[b[i].to]=dis[now]+b[i].cost;
if(vis[b[i].to]==0) d.push(b[i].to),vis[b[i].to]=1;
}
}
if(dis[t]==0x7f7f7f7f) return false;
return true;
}
int dfs(int u,int a){
if(u==t||a==0) return a;
vis[u]=1;
int f,flow=0;
for(int i=head[u];i!=-1;i=b[i].next)
if(vis[b[i].to]==0&&b[i].flow!=0&&dis[b[i].to]==dis[u]+b[i].cost){
f=dfs(b[i].to,min(b[i].flow,a));
b[i].flow-=f;b[i^1].flow+=f;
flow+=f;a-=f;
ans+=f*b[i].cost;
if(a==0) break;
}
return flow;
}
void dinic(){
while(bfs())
dfs(s,0x7f7f7f7f);
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&k);s=0,t=1001;
for(int i=1;i<=3*n;i++) scanf("%d",&data[i]);
for(int i=1;i<2*n;i++) add(i,i+1,k,0),add(i+1,i,0,0);
add(2*n+1,1,k,0),add(1,2*n+1,0,0);
add(2*n,2*n+2,k,0),add(2*n+2,2*n,0,0);
for(int i=1;i<=n;i++) add(i,i+n,1,-data[i+n]),add(i+n,i,0,data[i+n]);
for(int i=1;i<=n;i++) add(2*n+1,i,1,-data[i]),add(i,2*n+1,0,data[i]);
for(int i=1;i<=n;i++) add(i+n,2*n+2,1,-data[2*n+i]),add(2*n+2,i+n,0,data[2*n+i]);
add(s,2*n+1,k,0),add(2*n+1,s,0,0);add(2*n+2,t,k,0),add(t,2*n+2,0,0);
dinic();
printf("%d",-ans);
}
有下界限制一下的取值即可。