题意
题解
最大最小费用流直接求解。
建图:
设源点s,汇点t。
对每个源点s与人i连边,边流量为1,费用为0,用来控制每个人只能做一个工作。
对于每个工作j与汇点t连边,边流量为1,费用为0,用来控制每个工作只能做一次。
对每个人i,工作j建边,边流量为1,费用为效益即权值。
直接跑最小费用流即可求得最小值。
然后将最小费用流改为最大费用流,即按最长路进行增广。
记得对边进行复原。
code
#include <bits/stdc++.h> #define reg register #define ll long long #define ull unsigned long long #define pii pair<int,int> #define inf 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) #define ios ios::sync_with_stdio(false) #define rep(i,l,r) for(int i=(l);i<(r);i++) using namespace std; const int maxn = 200 + 10; const int mod = 1e9 + 7; struct Edge{ int to, cap, cost; int nxt; }edges[maxn * maxn]; int head[maxn],tot; int vis[maxn],pre[maxn],dis[maxn]; void addedge(int u,int v,int f,int c) { edges[tot] = {v,f,c,head[u]}; head[u] = tot++; } void addedges(int u,int v,int f,int c) { addedge(u,v,f,c); addedge(v,u,0,-c); } bool spfa(int s,int t) { memset(pre,-1,sizeof(pre)); fill(dis,dis+maxn,inf); memset(vis,0,sizeof(vis)); queue<int> q; vis[s] = 1; dis[s] = 0; q.push(s); while(q.size()){ int hd = q.front(); q.pop(); vis[hd] = 0; for(int i = head[hd];~i;i = edges[i].nxt){ auto &e = edges[i]; if(e.cap > 0 && dis[e.to] > dis[hd] + e.cost){ dis[e.to] = dis[hd] + e.cost; pre[e.to] = i; if(!vis[e.to]){ vis[e.to] = 1; q.push(e.to); } } } } return ~pre[t]; } int mcmf(int s,int t){ int flow = 0; int cost = 0; while(spfa(s,t)){ int mf= inf; for(int i = pre[t];~i;i = pre[edges[i^1].to]){ mf = min(mf,edges[i].cap); } flow += mf; for(int i = pre[t];~i;i = pre[edges[i^1].to]){ edges[i].cap -= mf; edges[i^1].cap += mf; cost += mf * edges[i].cost; } } return cost; } bool spfamx(int s,int t) //最长路 { memset(pre,-1,sizeof(pre)); fill(dis,dis+maxn,-inf); memset(vis,0,sizeof(vis)); queue<int> q; vis[s] = 1; dis[s] = 0; q.push(s); while(q.size()){ int hd = q.front(); q.pop(); vis[hd] = 0; for(int i = head[hd];~i;i = edges[i].nxt){ auto &e = edges[i]; if(e.cap > 0 && dis[e.to] < dis[hd] + e.cost){ dis[e.to] = dis[hd] + e.cost; pre[e.to] = i; if(!vis[e.to]){ vis[e.to] = 1; q.push(e.to); } } } } return ~pre[t]; } int mxmf(int s,int t){ int flow = 0; int cost = 0; while(spfamx(s,t)){ int mf= inf; for(int i = pre[t];~i;i = pre[edges[i^1].to]){ mf = min(mf,edges[i].cap); } flow += mf; for(int i = pre[t];~i;i = pre[edges[i^1].to]){ edges[i].cap -= mf; edges[i^1].cap += mf; cost += mf * edges[i].cost; } } return cost; } int g[maxn][maxn]; int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); freopen("out","w",stdout); #endif int s = 0,t = maxn - 1; tot = 0; memset(head,-1,sizeof(head)); int n; cin>>n; for(int i = 1;i <= n;++i){ addedges(s,i*2-1,1,0); addedges(i*2,t,1,0); } for(int i = 1;i <= n;++i){ for(int j = 1;j <= n;++j){ cin>>g[i][j]; addedges(i*2-1,j*2,1,g[i][j]); } } int mi = mcmf(s,t); //复原网络图 tot = 0; memset(head,-1,sizeof(head)); for(int i = 1;i <= n;++i){ addedges(s,i*2-1,1,0); addedges(i*2,t,1,0); } for(int i = 1;i <= n;++i){ for(int j = 1;j <= n;++j){ addedges(i*2-1,j*2,1,g[i][j]); } } int mx = mxmf(s,t); printf("%d\n%d\n",mi,mx); return 0; }