哎,被这道题搞死啦,详细解释在代码中
//最小割模型。首先建网络流模型,建立源点s和终点t(分别代表这两块不同的芯片),然后把s和每个点之间连一条容量为1,方向从s到点的边(方向 //一定要确定,因为割的容量的定义),然后从每个点到终点连一条容量为1,方向为点到t的边,然后在有联系的 //两点之间建一条容量为1的无向边(即一对容量为1方向相反的有向边)。建图完成。那么,在这个网络流模型中的一个割 //就对应于一种选择方案,而此方案的花费即割的容量。原因如下:先看所有的点都没有联系的情况,那么所有点和s的边 //和t的边这两条边有且仅有一条边在割去的边的集合中,哪条边割去说明点在哪个芯片上,那么割的容量就等于总花费(根 //据我们所建的模型)。说明一个割就是一种方案。然后考虑有有联系的点。对于一对有联系的点如果选择了同一块芯片,那么 //他们之间的那对相反方向的边就不在割去的边的集合中,所以此时总的花费也是等于割的容量。如果选择了不同的芯片,那么 //他们之间的边就在割去的边的集合中,此时总的花费也等于个的容量。注意此时,那对双向边的容量并没有造成花费的重复计算 //因为割的容量只是所有从s到t的边的容量值和,那两条双向边中只有一条是算在容量中,这也是为什么连接双向而不是单项边的 //原因,因为单向边会造成割的容量小于实际花费,两个点之间的花费没有算在割的容量中。所以此题求最小花费就是求最小割的容量, //也即最大流的大小。数据量很大,用的是Dinic #include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int maxn=20003; const int maxe=900000; const int inf=1<<25; struct Edge { int from,to,next; }; Edge edges[maxe]; int p[maxn],num[maxn],flow[maxe],cap[maxe],d[maxn],cur[maxn],head[maxn]; int n,m,tot,s,t; bool bfs() { memset(d,-1,sizeof(d)); queue<int> q; q.push(s); d[s]=0; while(!q.empty()) { int x=q.front();q.pop(); for(int i=head[x];i!=-1;i=edges[i].next) { Edge& e=edges[i]; if(d[e.to]==-1&&cap[i]>flow[i]) { d[e.to]=d[x]+1; q.push(e.to); } } } if(d[t]!=-1) return true; else return false; } int dfs(int x,int a) { if(x==t||a==0) return a; int tflow=0,f; for(int i=cur[x];i!=-1;i=edges[i].next) { Edge& e=edges[i]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,cap[i]-flow[i])))>0) { flow[i]+=f; flow[i^1]-=f; tflow+=f; a-=f; if(a==0) break; } } return tflow; } int maxflow() { int tflow=0; while(bfs()) { memcpy(cur,head,(n+2)*sizeof(int)); tflow+=dfs(s,inf); } return tflow; } void addedge(int from,int to,int ecap) { edges[tot].from=from; edges[tot].to=to; cap[tot]=ecap; edges[tot].next=head[from]; head[from]=tot; tot++; edges[tot].from=to; edges[tot].to=from; cap[tot]=0; edges[tot].next=head[to]; head[to]=tot; tot++; } void init() { tot=0; memset(flow,0,sizeof(flow)); memset(cap,0,sizeof(cap)); memset(head,-1,sizeof(head)); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { s=0;t=n+1; int i,j,ga,gb,a,b,w; init(); for(i=1;i<=n;i++) { scanf("%d%d",&ga,&gb); addedge(0,i,ga); addedge(i,n+1,gb); } for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&w); addedge(a,b,w); addedge(b,a,w); } printf("%d\n",maxflow()); } return 0; }