这个思路是真的想不到。
一开始想的是源点到每个奶牛的容量为1,然后奶牛到drink和food可以建容量为1的边,但怎么连到汇点就不知道了。
神来之笔是,把源点跟所有food连边,然后food跟输入指定的奶牛连边,奶牛再按输入跟drink连边,所有drink再去跟汇点连边。【特定奶牛吃了food,再喝drink,再流到汇点 与 任意奶牛吃任意food,然后变成特定奶牛,然后喝指定drink,再到汇点是一回事!】
但这么做不对,因为我们还要保证每个奶牛为答案的贡献不超过1,所以要把【一个奶牛拆成两个】,所以是源->food->奶牛(左)->奶牛(右)->drink->汇。
拿vector实现了一次,这样的话网络流的所有实现方法我都写过一遍了
#include#include #include #include #define INF 2e9using namespace std;int N,F,D,T;struct edge{ int v,cap,reverse;};vector edges[1005];//邻接表 vector bian;//所有的边都存在里面 void addedge(int u,int v,int cap){ //u到v一条边,再加一条反向边 edge e; e.cap=cap; e.v=v; e.reverse=bian.size()+1;//这条边的反边将建在这条边之后(这条边建完后在bian.size()的位置) bian.push_back(e); edges[u].push_back(bian.size()-1); e.cap=0; e.v=u; e.reverse=bian.size()-1; bian.push_back(e); edges[v].push_back(bian.size()-1);}int layer[1005],vis[1005];bool count_layer(){ memset(layer,0,sizeof(layer)); deque q; layer[0]=1; q.push_back(0); while( !q.empty() ){ int u = q.front(); q.pop_front(); if( u==T ) return true; for(int i=0;i 0 ){ layer[v] = layer[u] + 1; q.push_back( v ); } } } return false;}int dinic(){ int max_flow=0; while( count_layer() ){ memset(vis,0,sizeof(vis)); deque q,path;//记录一路走过来的【点】和【边的索引】 q.push_back(0); vis[0]=1; while(!q.empty()){ int u = q.back(); if( u==T ){ int min_u,min_v,min_flow=INF; int p=0;//从0点出发 for(int i=0;i 0 ){ vis[e.v]=1; q.push_back( e.v ); path.push_back( edges[u][i] ); break; } } if(i==edges[u].size()) { q.pop_back(); path.pop_back(); } } } } return max_flow;}int main(){ //food编号1 - F //把一头牛拆成两头 //cows1编号F+1 - F+N //cows2编号F+N+1 - F+N+N //drink编号F+2N+1 - F+2N+D cin>>N>>F>>D; T=N+N+F+D+1; for(int i=1;i<=N;i++){ int fi,di,food,drink; cin>>fi>>di; for(int j=1;j<=fi;j++) cin>>food,addedge(food,F+i,1);//food到奶牛1建一条边 for(int j=1;j<=di;j++) cin>>drink,addedge(F+N+i,F+2*N+drink,1);//从奶牛2到drink建一条边 } for(int i=F+1;i<=F+N;i++) addedge(i,i+N,1);//奶牛1到奶牛2建一条边 for(int i=1;i<=F;i++) addedge(0,i,1);//从源点0到所有food建边 for(int i=F+2*N+1;i<=F+2*N+D;i++) addedge(i,T,1); //从所有drink到汇点F+D+2*N+1建边 cout<