poj3469 最小割
最大流之后S集合与T集合不在相连,即s不能到达T中的点。
对于同一个模块,Ai,Bi,Ai与源点相连,Bi与汇点相连。不同CPU间消耗的模块,相连。
由于最后模块只能在一个CPU中运行,所以要么与源点相连,要么与汇点相连,所以可看做最小割模型。
我原来的Dinic模板,不是多路增广,所以超时。然后向大神学习了一下,就用现在这个模板,快很多很多。
即是用一次增广代替了多次增广,到一个节点时就一次性地把与其相邻的所有边翻出来求增广的和,如果和为零,代表它已增广不出什么了,把这个点废掉即可。
#include<stdio.h> #include<string.h> #include<queue> #define maxn 20010 #define Emaxn 201000 #define INF 99999999 using namespace std; struct node { int to; int v; int flag; int next; }edge[(Emaxn+maxn)*4]; int pre[maxn],vis[maxn],index,n; void add(int x,int y,int z) { edge[index].to=y; edge[index].v=z; edge[index].flag=index+1; edge[index].next=pre[x]; pre[x]=index++; edge[index].to=x; edge[index].v=0; edge[index].flag=index-1; edge[index].next=pre[y]; pre[y]=index++; } void init() { index=1; memset(pre,-1,sizeof(pre)); } int dfs(int u,int low)//此处增加used值表示当前使用了多少 { int i,used=0; if(u==n+1) return low; for(i=pre[u];i!=-1&&used<low;i=edge[i].next) { if(vis[edge[i].to]==vis[u]+1&&edge[i].v) { int a=dfs(edge[i].to,min(low-used,edge[i].v)); edge[i].v-=a; edge[edge[i].flag].v+=a; used+=a; //原来此处返回导致不停增广,而现在更具used值多次增广,知道无法增广为止,节省很多时间。 } } if(!used)//如果当前的路不能增广了,该点就不需要被访问。 vis[u]=-1; return used; } int BFS() { int i; queue<int>q; memset(vis,-1,sizeof(vis)); vis[0]=0; q.push(0); while(!q.empty()) { int t=q.front(); q.pop(); for(i=pre[t];i!=-1;i=edge[i].next) { if(vis[edge[i].to]<0&&edge[i].v>0) { vis[edge[i].to]=vis[t]+1; q.push(edge[i].to); } } } if(vis[n+1]>0)return 1; return 0; } int main() { int i,m; while(~scanf("%d%d",&n,&m)) { init(); for(i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); add(0,i,x); add(i,n+1,y); } for(i=0;i<m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } int ans=0; while(BFS()) { while(1) { int a=dfs(0,INF); if(!a)break; ans+=a; } } printf("%d\n",ans); } }