LOJ#3097. 「SNOI2019」通信 最小费用流+主席树优化建图
如果做过软件开发,餐巾计划问题的话这题就秒切了.
还是类似的套路:借流思想.
正解的话就是无聊地上一个主席树优化建图就行.
维护一颗边权为正数地主席树,再维护一颗边权为负数的主席树就行.
主席树写了,感觉好恶心......
code:
#include <bits/stdc++.h>
#define N 3008
#define inf 1000000000
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int s,t,n,m,flow;
ll ans;
namespace mcmf
{
int a[N],flow2[N],inq[N];
ll d[N];
struct Edge
{
int u,v,cap,cost;
Edge(int u=0,int v=0,int cap=0,int cost=0):u(u),v(v),cap(cap),cost(cost){}
};
queue<int>q;
vector<int>G[N];
vector<Edge>edges;
inline void add(int u,int v,int cap,int cost)
{
edges.push_back(Edge(u,v,cap,cost));
edges.push_back(Edge(v,u,0,-cost));
int p=edges.size();
G[u].push_back(p-2);
G[v].push_back(p-1);
}
int spfa()
{
for(int i=0;i<N;++i) d[i]=flow2[i]=inf;
memset(inq,0,sizeof(inq));
d[s]=0,inq[s]=1,q.push(s);
while(!q.empty())
{
int u=q.front(); q.pop(),inq[u]=0;
for(int i=0;i<G[u].size();++i)
{
Edge e=edges[G[u][i]];
if(e.cap>0&&d[e.v]>d[u]+e.cost)
{
d[e.v]=d[u]+e.cost;
flow2[e.v]=min(flow2[u],e.cap);
a[e.v]=G[u][i];
if(!inq[e.v])
{
inq[e.v]=1;
q.push(e.v);
}
}
}
}
if(d[t]==inf) return 0;
int f=flow2[t];
flow+=f;
int u=edges[a[t]].u;
edges[a[t]].cap-=f;
edges[a[t]^1].cap+=f;
while(u!=s)
{
edges[a[u]].cap-=f;
edges[a[u]^1].cap+=f;
u=edges[a[u]].u;
}
ans+=(ll)d[t]*f;
return 1;
}
inline int maxflow() { while(spfa()); return flow; }
inline ll getcost() { return ans; }
};
int I1(int x) { return x; }
int I2(int x) { return x+n; }
int val[N];
int main()
{
// setIO("input");
int W;
scanf("%d%d",&n,&W);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
s=0,t=(n<<1)+1;
for(int i=1;i<=n;++i)
{
mcmf::add(s,I1(i),1,0);
mcmf::add(I2(i),t,1,0);
mcmf::add(s,I2(i),1,W);
}
for(int i=1;i<=n;++i)
{
for(int j=i+1;j<=n;++j)
{
int det=abs(val[i]-val[j]);
mcmf::add(I1(i),I2(j),1,det); // 直接借光
}
}
mcmf::maxflow();
printf("%lld\n",mcmf::getcost());
return 0;
}

浙公网安备 33010602011771号