题解:
把这两道题目放在一起写,因为做法是一样的。
两题都是经典的线性规划问题,但同时也都可以用费用流解决。
以志愿者招募这题为例,首先设第
i
i
i类志愿者有
x
i
x_i
xi人。
那么根据样例可以列出不等式:
{
x
1
≥
2
x
1
+
x
2
≥
3
x
2
+
x
3
≥
4
\begin{cases} x_1\geq2\\ x_1+x_2\geq3\\ x_2+x_3\geq4 \end{cases}
⎩⎪⎨⎪⎧x1≥2x1+x2≥3x2+x3≥4
我们的目标是使
2
x
1
+
5
x
2
+
2
x
3
2x_1+5x_2+2x_3
2x1+5x2+2x3最小。
把不等式改写成等式:
{
x
1
=
2
+
y
1
x
1
+
x
2
=
3
+
y
2
x
2
+
x
3
=
4
+
y
3
\begin{cases} x_1=2+y_1\\ x_1+x_2=3+y_2\\ x_2+x_3=4+y_3 \end{cases}
⎩⎪⎨⎪⎧x1=2+y1x1+x2=3+y2x2+x3=4+y3
然后再差分一下,同时保留第一个原式和最后一个不等式的符号取反,得:
{
x
1
=
y
1
+
2
x
2
=
−
y
1
+
y
2
+
1
−
x
1
+
x
3
=
−
y
2
+
y
3
+
1
−
x
2
−
x
3
=
−
y
3
−
4
\begin{cases} x_1=y_1+2\\ x_2=-y_1+y_2+1\\ -x_1+x_3=-y_2+y_3+1\\ -x_2-x_3=-y_3-4 \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x1=y1+2x2=−y1+y2+1−x1+x3=−y2+y3+1−x2−x3=−y3−4
再让全部符号变成正号,移项得:
{
x
1
=
y
1
+
2
x
2
+
y
1
=
y
2
+
1
x
3
+
y
2
=
x
1
+
y
3
+
1
y
3
+
4
=
x
2
+
x
3
\begin{cases} x_1=y_1+2\\ x_2+y_1=y_2+1\\ x_3+y_2=x_1+y_3+1\\ y_3+4=x_2+x_3 \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧x1=y1+2x2+y1=y2+1x3+y2=x1+y3+1y3+4=x2+x3
然后可以发现每个未知量都出现且仅出现了两次(这个由题目的性质决定),而且一次是在等号左边一次在右边,然后可以开始建图了,把每个等式看做是一个点,右边看做是流入量,左边看做是流出量,由于满足流量平衡,所以满足等式。因此流量的含义就是每个数的大小,如果是未知数,那么在它左边出现的式子向右边出现的式子连一条流量为
i
n
f
inf
inf,费用为
C
i
C_i
Ci的边,含义是
x
i
x_i
xi可以取无限大,每取一个有代价。如果是常数,就由源点补充或流向汇点。
跑费用流就可以了。
4842代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1010;
const LL inf=(1LL<<50);
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
LL ans=0;
int lx[Maxn],rx[Maxn],ly[Maxn],ry[Maxn],lz[Maxn],rz[Maxn];
int n,k,t1,t2,si[Maxn],ei[Maxn],st,ed;//t1 s t2 e
struct Edge{int x,y,next;LL d,c;}e[Maxn<<4];
int last[Maxn<<3],len=1;
void ins(int x,int y,LL d,LL c)
{
int t=++len;
e[t].x=x;e[t].y=y;e[t].d=d;e[t].c=c;
e[t].next=last[x];last[x]=t;
}
void addedge(int x,int y,LL d,LL c){ins(x,y,d,c);ins(y,x,0LL,-c);}
LL f[Maxn<<3];int pre[Maxn<<3];bool in[Maxn<<3];
bool spfa()
{
pre[st]=-1;
memset(in,false,sizeof(in));
memset(f,-63,sizeof(f));f[st]=0;
queue<int>q;q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();in[x]=false;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(e[i].d&&f[x]+e[i].c>f[y])
{
f[y]=f[x]+e[i].c;pre[y]=i;
if(!in[y])in[y]=true,q.push(y);
}
}
}
return f[ed]>-inf;
}
void work()
{
int x=ed;LL mn=inf;
while(pre[x]!=-1)
{
mn=min(mn,e[pre[x]].d);
x=e[pre[x]].x;
}
x=ed;
while(pre[x]!=-1)
{
e[pre[x]].d-=mn;e[pre[x]^1].d+=mn;
ans+=e[pre[x]].c*mn;
x=e[pre[x]].x;
}
}
int main()
{
n=read(),k=read(),t1=read(),t2=read();
st=(n-k+1)*2+2,ed=st+1;
for(int i=1;i<=n;i++)si[i]=read();
for(int i=1;i<=n;i++)ei[i]=read(),ans+=(LL)ei[i];
for(int i=1;i<=k;i++)lx[i]=1;
for(int i=n-k+1;i<=n;i++)rx[i]=(n-k+1)*2+1;
for(int i=1;i<=n-k;i++)lx[i+k]=rx[i]=(i<<1)+1;
for(int i=1;i<=n-k+1;i++)ly[i]=i<<1,ry[i]=(i<<1)-1;
for(int i=1;i<=n-k+1;i++)lz[i]=i<<1,rz[i]=(i<<1)+1;
for(int i=1;i<=n;i++)addedge(lx[i],rx[i],1,si[i]-ei[i]);
for(int i=1;i<=n-k+1;i++)addedge(ly[i],ry[i],inf,0LL);
for(int i=1;i<=n-k+1;i++)addedge(lz[i],rz[i],inf,0LL);
addedge(st,1,t1,0LL);
for(int i=2;i<(n-k+1)*2+1;i++)
if(i&1)addedge(i,ed,k-t1-t2,0LL);
else addedge(st,i,k-t1-t2,0LL);
addedge((n-k+1)*2+1,ed,k-t2,0LL);
while(spfa())work();
printf("%lld\n",ans);
for(int i=1;i<=n;i++)
if(e[i<<1].d)putchar('E');
else putchar('S');
}
1061代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1010;
const int Maxm=10010;
const LL inf=(1LL<<50);
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,st,ed;
LL a[Maxn],S[Maxm],T[Maxm],C[Maxm],ans=0;
struct Edge{int x,y,next;LL d,c;}e[Maxm<<2];
int last[Maxn<<1],len=1;
void ins(int x,int y,LL d,LL c)
{
int t=++len;
e[t].x=x;e[t].y=y;e[t].d=d;e[t].c=c;
e[t].next=last[x];last[x]=t;
}
void addedge(int x,int y,LL d,LL c){ins(x,y,d,c);ins(y,x,0LL,-c);}
LL f[Maxn<<1];int pre[Maxn<<1];bool in[Maxn<<1];
bool spfa()
{
pre[st]=-1;
memset(in,false,sizeof(in));
memset(f,63,sizeof(f));f[st]=0;
queue<int>q;q.push(st);
while(!q.empty())
{
int x=q.front();q.pop();in[x]=false;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(e[i].d&&f[x]+e[i].c<f[y])
{
f[y]=f[x]+e[i].c;pre[y]=i;
if(!in[y])in[y]=true,q.push(y);
}
}
}
return f[ed]<inf;
}
void work()
{
int x=ed;LL mn=inf;
while(pre[x]!=-1)
{
mn=min(mn,e[pre[x]].d);
x=e[pre[x]].x;
}
x=ed;
while(pre[x]!=-1)
{
e[pre[x]].d-=mn;e[pre[x]^1].d+=mn;
ans+=e[pre[x]].c*mn;
x=e[pre[x]].x;
}
}
int main()
{
n=read(),m=read();st=n+2,ed=n+3;
for(int i=1;i<=n;i++)a[i]=read(),addedge(i+1,i,inf,0);a[0]=a[n+1]=0;
for(int i=1;i<=m;i++)S[i]=read(),T[i]=read(),C[i]=read(),addedge(S[i],T[i]+1,inf,C[i]);
for(int i=1;i<=n+1;i++)
{
if(a[i]>a[i-1])addedge(st,i,a[i]-a[i-1],0);
else addedge(i,ed,a[i-1]-a[i],0);
}
while(spfa())work();
printf("%lld",ans);
}