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;
}
posted @ 2025-03-26 11:06  WuMin4  阅读(7)  评论(0)    收藏  举报