P6967 [NEERC2016]Delight for a Cat 题解
第一眼:这个是 dp ?
第二眼:神马 dp 神仙题啊,太弱了诶
第三眼:一发上网络流建模!
于是就有了这篇题解。
这里给出一个线性规划理解的最大流做法。
假设猫睡了 $n$ 天,则有收益 $\sum_{i=1}^n s_i$ ,然后所做的事情就是把某些天的睡觉改成吃饭。
设 $x_i\in\{0, 1\}$ 表示第 $i$ 天干的事情。 $x_i=0$ 表示睡觉, $x_i=1$ 表示吃饭。
依题意得
$\forall i\in[1,n-k+1],
me\leqslant\sum_{j=i}^{i+k-1}x_j\leqslant k-ms$
$\forall i\in[1,n]\cap\mathbb{Z},x_i\in\{0,1\}$
$\text{maximize}\{\sum_{i=1}^n (e_i-s_i)x_i\}$
再设变量 $y$ 和 $z$ 。得:
$x_1+x_2+...+x_k=me+y_1$
$x_1+x_2+...+x_k=k-ms-z_1$
$x_2+x_3+...+x_{k+1}=me+y_2$
$x_2+x_3+...+x_{k+1}+z_2=k-ms-z_2 $
$...$
$x_{n-k+1}+x_{n-k+2}+...+x_{n-1}+x_n=me+y_{n-k+1}$
$x_{n-k+1}+x_{n-k+2}+...+x_{n-1}+x_n=k-ms-z_{n-k+1}$
增加恒等式 $0=0$ ,并且设常数 $C=k-ms-me$ 。得:
$x_1+x_2+...+x_k=me+y_1 $
$y_1+z_1=C $
$x_{k+1}+C=x_1+y_2+z_1 $
$y_2+z_2=C $
$... $
$x_n+C=x_{n-k}+y_{n-k+1}+z_{n-k} $
$y_{n-k+1}+z_{n-k+1}=C$
$k-ms=x_{n-k+1}+x_{n-k+2}+...+x_n+z_{n-k+1} $
所有未知量和满足“流入=流出”,每一个式子也可以看作“流入=流出”,所以使用网络流算法。
为什么不用单纯型?因为不容易输出方案。~~其实是本人不会~~
因为有容量,还有费用 $e_i-s_i$ (仅限于表示 $x_i$ 的边),所以使用**最大费用最大流**来求解。
答案为 $\sum s_i + \text{MCMF}$ 。
如何判断方案?找出所有表示 $x_i$ 的边,满流就是吃饭,空流就是睡觉。
由于本人使用EK算法,所以是 $\Theta(nm^2)$ 。
# 代码时光到~
#include<cstdio> #include<cstring> #include<iostream> #define int long long #define inf 0x3f3f3f3f3f3f3f3f using namespace std; int n,k,ms,me,_s[1010],_e[1010],sum; bool vis[50010];int id[1010]; int front,rear,q[10000010]; int cnt=-1,head[50010],d[50010]; int s,t,p1[50010],p2[50010]; int pre[100010],ver[100010],cap[100010],cost[100010]; void adde(int u,int v,int f,int w){ pre[++cnt]=head[u];ver[cnt]=v;cap[cnt]=f;cost[cnt]=w;head[u]=cnt; pre[++cnt]=head[v];ver[cnt]=u;cap[cnt]=0;cost[cnt]=-w;head[v]=cnt; } bool SPFA(int src,int &fs,int &cs){ front=1,rear=1; memset(d,0x3f,sizeof(d)); memset(p1,-1,sizeof(p1)); memset(p2,-1,sizeof(p2)); memset(vis,false,sizeof(vis)); q[++rear]=src;vis[src]=true;d[src]=0; while(front<rear){ int u=q[++front];vis[u]=false; for(int i=head[u];i!=-1;i=pre[i]){ int v=ver[i]; if(cap[i]<=0)continue; if(d[v]>d[u]+cost[i]){ d[v]=d[u]+cost[i]; p1[v]=u;p2[v]=i; if(!vis[v])vis[v]=true,q[++rear]=v; } } } if(p1[t]==-1)return false; int k=t;fs=0x3f3f3f3f3f3f3f3f; while(k!=s&&p1[k]!=-1)fs=min(fs,cap[p2[k]]),k=p1[k]; if(fs<=0||k!=s)return false; k=t;cs=0; while(k!=s){ cs=cs+cost[p2[k]]; cap[p2[k]]-=fs; cap[p2[k]^1]+=fs; k=p1[k]; } cs=cs*fs;return true; } void mincost_flow(int &fsum,int &csum){ int ff,cc; fsum=0,csum=0; while(SPFA(s,ff,cc)){ fsum=fsum+ff; csum=csum+cc; } } signed main(){ memset(head,-1,sizeof(head)); scanf("%lld%lld%lld%lld",&n,&k,&ms,&me); for(int i=1;i<=n;i++)scanf("%lld",&_s[i]); for(int i=1;i<=n;i++)scanf("%lld",&_e[i]); for(int i=1;i<=n;i++)sum+=_s[i],_e[i]-=_s[i]; s=0,t=(n-k+1<<1|1)+1; for(int i=1;i<=n-k+1;i++)adde(i<<1|1,i<<1,inf,0);//zi for(int i=1;i<=n-k+1;i++)adde((i-1)<<1|1,i<<1,inf,0);//yi for(int i=1;i<=n-k;i++)adde(s,i<<1|1,k-ms-me,0);//C for(int i=1;i<=n-k+1;i++)adde(i<<1,t,k-ms-me,0);//C for(int i=1;i<=k;i++){id[i]=cnt+1; adde(min(i<<1|1,t-1),1,1,-_e[i]); } for(int i=1;i<=n-k;i++){id[i+k]=cnt+1; adde(min((i+k)<<1|1,t-1),i<<1|1,1,-_e[k+i]); } adde(1,t,me,0);adde(s,t-1,k-ms,0); int tmpf=0,tmps=0;mincost_flow(tmpf,tmps);sum-=tmps; printf("%lld\n",sum); for(int i=1;i<=n;i++)printf(cap[id[i]]?"S":"E"); putchar('\n'); return 0; }

浙公网安备 33010602011771号