[COGS 740]分配问题
转载请注明出处:http://danihao123.is-programmer.com/
很明显是二分图最大权匹配。可以用匈牙利算法求解,但我比较弱……所以就写了个费用流。
注意最优解和最差解都要给出!
代码:
#include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int maxn=205; namespace MCMF{ struct Edge{ int u,v,cap,flow,cost; }; vector<Edge> edges; vector<int> G[maxn]; int m; inline void AddEdge(int u,int v,int cap,int cost){ edges.push_back((Edge){u,v,cap,0,cost}); edges.push_back((Edge){v,u,0,0,-cost}); m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } inline void ClearGraph(){ register int i; edges.clear(); for(i=0;i<maxn;i++) G[i].clear(); } int a[maxn]; bool inQueue[maxn]; int d[maxn],p[maxn]; bool BellmanFord(int s,int t,long long& cost){ register int i,u; queue<int> Q; memset(d,0x7f,sizeof(d)); memset(inQueue,0,sizeof(inQueue)); d[s]=0; inQueue[s]=true; p[s]=0; a[s]=0x7f7f7f7f; Q.push(s); while(!Q.empty()){ u=Q.front(); Q.pop(); inQueue[u]=false; for(i=0;i<G[u].size();i++){ Edge& e=edges[G[u][i]]; if(e.cap>e.flow && d[e.v]>d[u]+e.cost){ d[e.v]=d[u]+e.cost; p[e.v]=G[u][i]; a[e.v]=min(a[u],e.cap-e.flow); if(!inQueue[e.v]){ Q.push(e.v); inQueue[e.v]=true; } } } } if(d[t]==0x7f7f7f7f) return false; cost+=((long long)d[t])*((long long)a[t]); for(u=t;u!=s;u=edges[p[u]].u){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } return true; } long long MincostMaxflow(int s,int t){ register long long ans=0; while(BellmanFord(s,t,ans)); return ans; } }; int A[105][105]; int main(){ int n; register int i,j; freopen("job.in","r",stdin); freopen("job.out","w+",stdout); scanf("%d",&n); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ scanf("%d",&A[i][j]); MCMF::AddEdge(i,j+n,1,A[i][j]); } for(i=1;i<=n;i++) MCMF::AddEdge(0,i,1,0); for(i=n+1;i<=2*n;i++) MCMF::AddEdge(i,2*n+1,1,0); printf("%lld\n",MCMF::MincostMaxflow(0,2*n+1)); MCMF::ClearGraph(); for(i=1;i<=n;i++) for(j=1;j<=n;j++){ MCMF::AddEdge(i,j+n,1,-A[i][j]); } for(i=1;i<=n;i++) MCMF::AddEdge(0,i,1,0); for(i=n+1;i<=2*n;i++) MCMF::AddEdge(i,2*n+1,1,0); printf("%lld\n",-(MCMF::MincostMaxflow(0,2*n+1))); return 0; }