http://poj.org/problem?id=1149 题目
讲解:
(建图)https://blog.csdn.net/hikean/article/details/9956465
如何建图(第一步初始)
然后怎样简化这个图,尤其是为什么在客户之间连边这个很巧妙,这样让猪能够自由流动
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<cstdio> #include<queue> #include<map> #include<vector> #include<set> using namespace std; const int maxn=1300; const int INF=0x3fffffff; typedef long long LL; typedef unsigned long long ull; //dinic int d[110]; int f[110][110]; int cow[maxn]; int pre[maxn]; int n,m; int bfs(int s){ int q[maxn]; q[0]=0; //模拟队列 //0是超级源点 memset(d,-1,sizeof(d)); //初始化层次 d[s]=0; int front=0,rear=1; while(front<rear){ int t=q[front++]; for(int j=0;j<=n+1;j++){ if(d[j]==-1&&f[t][j]>0){ //没访问过而且有连边 d[j]=d[t]+1; q[rear++]=j; } } } if(d[n+1]>=0) return 1; ///n+1是超级汇点 else return 0; } int dinic(int t,int sum){ if(t==n+1) return sum; int os=sum; for(int i=0;i<=n+1&∑i++){ //sum=0的时候可以自动退出 if(d[i]==d[t]+1&&f[t][i]>0){ //可行流 int a=dinic(i,min(sum,f[t][i])); f[t][i]-=a; f[i][t]+=a; sum-=a; } } return os-sum; } int main(){ scanf("%d %d",&m,&n); int tot=0; for(int i=1;i<=m;i++){ //这个是每个猪圈的初始猪数 scanf("%d",&cow[i]); tot+=cow[i]; } int num,x,y; for(int i=1;i<=n;i++){ scanf("%d",&num); for(int j=1;j<=num;j++){ scanf("%d",&x); if(pre[x]==0) f[0][i]+=cow[x]; // 当猪圈被第一次打开时,在源点与当前顾客之间连接一条边,容量为该猪圈的猪的头数 else f[pre[x]][i]=tot;//当某个猪圈 不是被第一次打开时,在上一个打开该猪圈的顾客与当前打开该猪圈的顾客之间连接一条边,容量为无穷大 pre[x]=i; } scanf("%d",&y); f[i][n+1]=y; //在每个顾客与汇点之间连接一条边,容量为该顾客要买猪的头数 } int res=0; while(bfs(0)){ res+=dinic(0,INF); } printf("%d",res); return 0; }