二分图最小权完美匹配。
一个最小费用流就能跑了,记住检查一下,容量是否跑满,如果没有跑满,就说明没有完美匹配。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 500+10; const int maxm = 50000 + 10; const int inf = 0x3f3f3f3f; int g[maxn],v[maxm],f[maxm],c[maxm],nex[maxm],eid; int id[maxn][2],vid; int n,ans,S,T; bool inque[maxn]; int q[maxm],dist[maxn],pre[maxn]; void addedge(int a,int b,int F,int C) { v[eid]=b; f[eid]=F; c[eid]=C; nex[eid]=g[a]; g[a]=eid++; v[eid]=a; f[eid]=0; c[eid]=-C; nex[eid]=g[b]; g[b]=eid++; } bool build() { if(scanf("%d",&n)==1&&n) { memset(g,-1,sizeof(g)); eid=0; vid=0; S=++vid; T=++vid; for(int i=1;i<=n;i++) { id[i][0]=++vid; id[i][1]=++vid; addedge(S,id[i][0],1,0); addedge(id[i][1],T,1,0); } for(int i=1,j,d;i<=n;i++) while(scanf("%d",&j) && j) { scanf("%d",&d); addedge(id[i][0],id[j][1],1,d); } return true; } return false; } bool SPFA() { int u,l,r; l=r=0; memset(dist,0x3f,sizeof(dist)); dist[S]=0; inque[q[r++]=S]=1; while(l<r) { inque[u=q[l++]]=0; for(int i=g[u];~i;i=nex[i]) if(f[i] && dist[v[i]]>dist[u]+c[i]) { dist[v[i]]=dist[u]+c[i]; pre[v[i]]=i; if(!inque[v[i]]) inque[q[r++]=v[i]]=1; } } return dist[T]<inf; } int augment() { int aug=inf,res=0; for(int i=T;i!=S;i=v[pre[i]^1]) aug=min(aug,f[pre[i]]); for(int i=T;i!=S;i=v[pre[i]^1]) { f[pre[i]]-=aug; f[pre[i]^1]+=aug; res+=aug*c[pre[i]]; } ans+=aug; return res; } void solve() { ans=0; int res=0; while(SPFA()) res+=augment(); if(ans!=n) printf("N\n"); else printf("%d\n",res); } int main() { while(build()) solve(); return 0; }
时间: 2024-10-18 14:13:25