目录
显示
题目链接
https://uva.onlinejudge.org/external/11/p1194.pdf
https://www.luogu.org/problem/UVA1194
题解
我们建立一个二分图,左部点代表 A 机器的所有模式,右部点代表 B 机器的所有模式。
对于一个任务 \(i\),我们从左部点 \(a_i\) 向右部点 \(b_i\) 连一条边。
容易看出,我们求的是该二分图的最小点覆盖,而最小点覆盖=最大匹配,求出它的最大匹配即可。
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define INF 0x3f3f3f3f using namespace std; struct edge { int v,w,next; }e[10005]; int head[205],cur[205],dist[205],s,t,cnt; void addedge(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } bool bfs() { queue<int> q; memcpy(cur,head,sizeof(cur)); memset(dist,INF,sizeof(dist)); dist[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].w&&dist[e[i].v]>dist[u]+1) { dist[e[i].v]=dist[u]+1; q.push(e[i].v); } } return dist[t]!=INF; } int dfs(int u,int flow) { if(u==t)return flow; int used=0; for(int i=cur[u];i;i=e[i].next) { cur[u]=i; int v=e[i].v; if(e[i].w&&dist[v]==dist[u]+1) { int w=dfs(v,min(flow-used,e[i].w)); if(w) { used+=w; e[i].w-=w; e[i^1].w+=w; if(used==flow)break; } } } return used; } int main() { int n,m,k; while(~scanf("%d",&n)) { if(!n)return 0; cnt=1; memset(head,0,sizeof(head)); scanf("%d%d",&m,&k); s=n+m+1,t=n+m+2; for(int i=1;i<=k;i++) { int tmp,x,y; scanf("%d%d%d",&tmp,&x,&y); addedge(x,y+n,1); addedge(y+n,x,0); } for(int i=1;i<=n;i++) { addedge(s,i,1); addedge(i,s,0); } for(int i=1;i<=m;i++) { addedge(i+n,t,1); addedge(t,i+n,0); } int ans=0; while(bfs()) ans+=dfs(s,INF); printf("%d\n",ans); } }