任务安排

link

最小费用最大流的应用(我似乎是第一次实践费用流?)。

按照题目的说法,每个人都只能操作一台机器,每台机器也只能被一个人操作,这比较简单,把两类节点分别向源汇点连1边即可。但它要求收益最大,但最长路是不好跑的(即使它是DAG),所以考虑给每条边的边权取一个相反数,这样就可以让问题变成最小费用最大流了。SPFA是可以做负权图哒。

#include<bits/stdc++.h>
//#define feyn
const int N=1010;
const int M=N*N;
const int maxn=1e9;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

int m,n,a[N],b[N],ss,tt,cnt;

struct edge{
	int t,v1,v2,next;
}e[M];
int head[N*3],esum=1;
inline void adde(int fr,int to,int v1,int v2){
	e[++esum]=(edge){to,v1,v2,head[fr]};head[fr]=esum;
}
inline void add(int fr,int to,int v1,int v2){
	//printf("%d %d %d %d\n",fr,to,v1,v2);
	adde(fr,to,v1,v2);adde(to,fr,0,-v2);
}

queue<int>q;
int dis[N];int tot;
bool inq[N],vis[N];
inline bool check(){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	memset(inq,0,sizeof(inq));
	inq[ss]=true;dis[ss]=0;q.push(1);
	while(!q.empty()){
		int wh=q.front();q.pop();inq[wh]=false;
		//printf("%d %d\n",wh,dis[wh]);
		for(int i=head[wh],th;i;i=e[i].next){
			if(e[i].v1==0)continue;
			int now=dis[wh]+e[i].v2;
			if(dis[th=e[i].t]<=now)continue;
			dis[th]=now;if(inq[th]==false)inq[th]=true,q.push(th);
		}
	}
	return dis[tt]<1e8;
}
int cost;
inline int dinic(int wh,int val){
	//printf("%d %d\n",wh,val);
	if(wh==tt)return cost+=dis[wh]*val,val;
	int used=0;vis[wh]=true;
	for(int i=head[wh],th;i;i=e[i].next){
		if(vis[th=e[i].t]||dis[th]!=dis[wh]+e[i].v2||e[i].v1==0)continue;
		int now=dinic(th,min(val,e[i].v1));
		if(now)used+=now,val-=now,e[i].v1-=now,e[i^1].v1+=now;
	}
	return used;
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	ss=++cnt;tt=++cnt;
	for(int i=1;i<=m;i++)a[i]=++cnt,b[i]=++cnt;
	for(int i=1;i<=m;i++)add(ss,a[i],1,0),add(b[i],tt,1,0);
	int s1,s2,s3;
	while(~scanf("%d%d%d",&s1,&s2,&s3))add(a[s1],b[s2],1,-s3);
	
	int ans=0;
	while(check())ans+=dinic(ss,maxn);
	printf("%d %d\n",ans,-cost);
	
	return 0;
}
posted @ 2022-07-09 17:02  Feyn618  阅读(36)  评论(0编辑  收藏  举报