CF1437C Chef Monocarp
CF1437C Chef Monocarp
思路
每个时间只能选一个物品,不同的时间选物品有不同的代价,\(n\le 200\),于是直接无脑费用流。
建立经典二分图模型,源点 \(S\) 向每个物品连边,每个时间向汇点 \(T\) 连边,容量为 \(1\),费用为 \(0\)。每个物品向每个时间连边,容量为 \(1\),费用为该时间取出该物品的不美味度。
当菜品最佳时间均为 \(n\) 时时间范围最多取到了 \(\lceil\frac{3}{2}n\rceil\),我取了 \(2n\),需要开 \(3\) 倍空间,需要注意。
代码
#include <bits/stdc++.h>
using namespace std;
namespace mf{
const int N=605,INF=0x3f3f3f3f;
struct node{int x,w,c,rev;};
vector<node> t[N];
int dis[N],flow[N],maxflow,mincost;
node *pre[N];
bool vis[N];
int n,S,T;
void init(int nn){
memset(flow,0,sizeof(flow));
for(int i=1;i<=nn+2;i++)
t[i].clear();
n=nn+2,S=nn+1,T=nn+2;
}
void add(int x,int y,int w,int c){
t[x].push_back({y,w,c,t[y].size()});
t[y].push_back({x,0,-c,t[x].size()-1});
}
bool spfa(){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
dis[S]=0,vis[S]=true,flow[S]=INF,q.push(S);
while(!q.empty()){
int u=q.front();
q.pop(),vis[u]=false;
for(node&v:t[u]){
if(v.w&&dis[v.x]>dis[u]+v.c){
dis[v.x]=dis[u]+v.c;
flow[v.x]=min(flow[u],v.w);
pre[v.x]=&v;
if(!vis[v.x])
vis[v.x]=true,q.push(v.x);
}
}
}
return dis[T]!=INF;
}
void upd(){
int x=T;
while(x!=S){
node *i=pre[x];
i->w-=flow[T];
t[i->x][i->rev].w+=flow[T];
x=t[i->x][i->rev].x;
}
maxflow+=flow[T],mincost+=flow[T]*dis[T];
}
pair<int,int> ek(){
maxflow=mincost=0;
while(spfa()) upd();
return {maxflow,mincost};
}
}
int q,n;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr),cout.tie(nullptr);
cin>>q;
while(q--){
cin>>n;
mf::init(3*n);
for(int i=1;i<=2*n;i++)
mf::add(i+n,mf::T,1,0);
for(int x,i=1;i<=n;i++){
cin>>x;
mf::add(mf::S,i,1,0);
for(int j=1;j<=2*n;j++)
mf::add(i,j+n,1,abs(j-x));
}
cout<<mf::ek().second<<endl;
}
return 0;
}

浙公网安备 33010602011771号