题目链接:
题目大意:
给定n男n女,n男与n女两两之间有一个幸福值H[i][j],请求出他们之间的完美匹配并且输出匹配的必须边的端点.($nleq80$)
solution:
对于完美匹配,我们可以跑最大费用最大流.至于求必须边,不难发现第一次跑完完美匹配后,男女点之间只流过了n条边,所以剩余的边肯定不是必须边.由于n值较小,所以我们可以一一枚举第一次费用流所流过的边,断边观察最大费用是否改变,若改变则统计答案即可.
code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #define R register #define next exnttttttttttttttttttttt #define debug puts("mlg") using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void write(ll x); inline void writesp(ll x); inline void writeln(ll x); ll n,S,T; ll H[88][88]; ll to[50000],from[50000],head[50000],next[50000],tot=1,c[50000],w[50000]; inline void add(ll x,ll y,ll u,ll v){ to[++tot]=y;from[tot]=x;next[tot]=head[x];head[x]=tot;c[tot]=u;w[tot]=v; } ll d[50000],last[50000],incf[50000],pre[50000]; bool vis[50000]; queue<ll>q; inline bool spfa(){ for(R ll i=1;i<=T;i++) d[i]=-1000000; memset(vis,0,sizeof vis); while(q.size())q.pop(); incf[S]=12534567984654089; d[S]=0; q.push(S);pre[T]=-1; while(!q.empty()){ ll x=q.front();q.pop();vis[x]=false; for(R ll i=head[x],ver;i;i=next[i]){ ver=to[i]; if(!c[i]) continue; if(d[ver]<d[x]+w[i]){ d[ver]=d[x]+w[i]; incf[ver]=min(incf[x],c[i]); last[ver]=i; pre[ver]=x; if(!vis[ver]){ vis[ver]=true; q.push(ver); } } } } return d[T]!=-1000000; } ll ans,maxflow; inline void update(){ ll x=T; while(x!=S){ c[last[x]]-=incf[T]; c[last[x]^1]+=incf[T]; x=pre[x]; } ans+=d[T]*incf[T]; maxflow+=incf[T]; } ll TOT,D[5000]; bool check[90][90]; int main(){ freopen("match.in","r",stdin); freopen("match.out","w",stdout); n=read(); for(R ll i=1;i<=n;i++){ for(R ll j=1;j<=n;j++){ H[i][j]=read(); } } S=n*2+1,T=S+1; for(R ll i=1;i<=n;i++){ add(S,i,1,0);add(i,S,0,0); add(i+n,T,1,0);add(T,i+n,0,0); } for(R ll i=1;i<=n;i++){ for(R ll j=1;j<=n;j++){ add(i,j+n,1,H[i][j]); add(j+n,i,0,-H[i][j]); } } while(spfa()) update(); writeln(ans); ll Ans=ans; for(R ll i=2;i<tot;i+=2){ if(!c[i]&&from[i]!=S&&to[i]!=T) D[++TOT]=i; c[i]+=c[i^1];c[i^1]=0; } for(;TOT;--TOT){ for(R ll i=2;i<tot;i+=2) c[i]+=c[i^1],c[i^1]=0; ll C=c[D[TOT]];c[D[TOT]]=0,ans=0; while(spfa()) update(); if(Ans!=ans){ check[from[D[TOT]]][to[D[TOT]]-n]=true; } c[D[TOT]]+=C; } for(R ll i=1;i<=n;i++){ for(R ll j=1;j<=n;j++) if(check[i][j]) writesp(i),writeln(j); } } inline ll read(){ ll x=0,t=1;char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') t=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*t; } inline void write(ll x){ if(x<0){putchar('-');x=-x;} if(x<=9){putchar(x+'0');return;} write(x/10);putchar(x%10+'0'); } inline void writesp(ll x){ write(x);putchar(' '); } inline void writeln(ll x){ write(x);putchar(' '); }