思路:將牛拆開,分別一一對應,然後構建有向圖: S(源點) 食物(1-F) 牛(1——N) 牛(1-N) 飲料(1-D) 匯點T 單向邊,每條邊容量為1 ,轉換為最大流問題: 至於為什麼要把對應的牛拆成兩個頂點:保證一條牛不會被分配多組食物和飲料 代碼:
#include<iostream> #include<queue> #include<cstring> using namespace std; const int MAXN=101; bool likeF[MAXN][MAXN]; //食物的喜好 bool likeD[MAXN][MAXN]; const int MAXV=MAXN*4+2; int c[MAXV][MAXV],N,F,D; //c:鄰接矩陣 bool visited[MAXV]; int pre[MAXV]; bool bfs(int s,int t) { memset(visited,0,sizeof(visited)); queue<int> que; que.push(s); visited[s]=1; while(!que.empty()) { int p=que.front(); que.pop(); for(int i=0;i<=t;i++) { if( !visited[i]&& c[p][i]>0){ que.push(i); visited[i]=1; pre[i]=p; if(i==t) return 1; } } } return 0; } int ek(int s,int t) { int max_flow=0; while(1) { if(!bfs(s,t)) break; int i=t; while(i!=s) { c[pre[i]][i]-=1; c[i][pre[i]]+=1; i=pre[i]; } max_flow++; } return max_flow; } void solve() { // 0:N-1 食物一側的牛 // N:2N-1 飲料一側的牛 // 2N:2N+F-1 食物 // 2N+F:2N+F+D-1 飲料 // 構建圖模型 int s=N*2+F+D,t=s+1; for(int i=0;i<F;i++){ //s與食物之間連邊 c[s][2*N+i]=1; } for(int i=0;i<D;i++){ //飲料和t之間連邊 c[2*N+F+i][t]=1; } for(int i=0;i<N;i++){ c[i][i+N]=1; for(int j=0;j<F;j++){ if(likeF[i][j]) c[2*N+j][i]=1; } for(int j=0;j<D;j++){ if(likeD[i][j]) c[i+N][j+2*N+F]=1; } } cout<<ek(s,t)<<endl; } int main() { while(cin>>N>>F>>D) { memset(likeD,0,sizeof(likeD)); memset(likeF,0,sizeof(likeF)); for(int i=0;i<N;i++){ int fn,dn; cin>>fn>>dn; for(int j=0;j<fn;j++) { int f; cin>>f; likeF[i][f-1]=1; } for(int j=0;j<dn;j++){ int d; cin>>d; likeD[i][d-1]=1; } } memset(c,0,sizeof(c)); solve(); } return 0; }