这又是一道我没有当场想出来的题
题面
https://www.luogu.org/problemnew/show/P4016
题解
$S$连初始状态,末状态连$T$,转移边流量为$INF$,费用为$1$。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#define N 105
#define INF 1000000007
#define T (n+1)
#define S 0
#define LL long long
#define ri register int
using namespace std;
int n,a[N];
struct graph {
vector<int> to,w,c;
vector<int> ed[N];
LL dis[N]; int cur[N];
bool vis[N];
void add_edge(int a,int b,int aw,int ac) {
to.push_back(b); w.push_back(aw); c.push_back(ac); ed[a].push_back(to.size()-1);
to.push_back(a); w.push_back(0); c.push_back(-ac); ed[b].push_back(to.size()-1);
}
bool spfa() {
memset(dis,0x2f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
dis[S]=0;q.push(S);vis[S]=1;
while (!q.empty()) {
int x=q.front(); q.pop();
for (ri i=0;i<ed[x].size();i++) {
int e=ed[x][i];
if (dis[to[e]]>dis[x]+c[e] && w[e]) {
dis[to[e]]=dis[x]+c[e];
if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]);
}
}
vis[x]=0;
}
return dis[T]<INF;
}
int dfs(int x,int lim) {
if (x==T || !lim) return lim;
LL sum=0; vis[x]=1;
for (ri &i=cur[x];i<ed[x].size();i++) {
int e=ed[x][i];
if (dis[x]+c[e]==dis[to[e]] && w[e] && !vis[to[e]]) {
int f=dfs(to[e],min(lim,w[e]));
w[e]-=f; w[1^e]+=f;
lim-=f; sum+=f;
if (!lim) return sum;
}
}
return sum;
}
LL zkw() {
LL ret=0;
while (spfa()) {
memset(vis,0,sizeof(vis));
memset(cur,0,sizeof(cur));
ret+=dfs(S,INF)*dis[T];
}
return ret;
}
} G;
int suc(int x) {
x++;
if (x==n+1) return 1; else return x;
}
int pre(int x) {
x--;
if (x==0) return n; else return x;
}
int main() {
scanf("%d",&n);
int sum=0;
for (ri i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
int av=sum/n;
for (ri i=1;i<=n;i++) {
G.add_edge(S,i,a[i],0);
G.add_edge(i,T,av,0);
G.add_edge(i,suc(i),INF,1);
G.add_edge(i,pre(i),INF,1);
}
cout<<G.zkw()<<endl;
}
来源:https://www.cnblogs.com/shxnb666/p/11187930.html