分析:
这类问题的一遍描述,把一些对象分成两组,划分有一些代价,问最小代价。一般性的思路是,
把这两组看成是S点和T点,把划分的代价和割边的容量对应起来求最小割。
把S和可模版tem之间到达关系看作是属于核A,对称地,T对应B。模块tem安装在A上代价Ai,就是割断tem和T,连一条tem到T的容量为Ai的边。
相应地,对于Bi,连一条S到tem容量为Bi的边。当ai安装在A上,bi安装在B上,也就是s - ai, bi - t(-表示可到达),这时候如果有额外花费wi
那么ai - bi之间连上容量为wi的边,反过来bi和ai对换一下也是类似的。
输入很大,光是I/O就能优化1s,ISAP会更快。
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> using namespace std; const int maxv = 2e4+2, maxe = 4e5+maxv*4; int hd[maxv],to[maxe],nx[maxe],ec,cap[maxe]; #define eachEage int i = hd[u]; ~i; i = nx[i] inline void add(int u,int v, int cp) { nx[ec] = hd[u]; to[ec] = v; cap[ec] = cp; hd[u] = ec++; } inline void Add(int u,int v,int cp) { add(u,v,cp); add(v,u,0); } int lv[maxv], q[maxv]; bool vis[maxv]; int S,T; bool bfs() { memset(vis,0,sizeof(bool)*(T+1)); int l = 0, r = 0; lv[q[r++] = S] = 0; vis[S] = true; while(l<r){ int u = q[l++]; for(eachEage){ int v = to[i]; if(!vis[v] && cap[i]){ lv[q[r++] = v] = lv[u] + 1; vis[v] = true; } } } return vis[T]; } int cur[maxv]; int aug(int u,int a) { if(u == T || !a) return a; int flow = 0,f; for(int &i = cur[u]; ~i; i = nx[i]){ int v = to[i]; if(lv[v] == lv[u]+1 && (f = aug(v, min(a,cap[i])))){ flow += f; a -= f; cap[i] -= f; cap[i^1] += f; if(!a) break; } } return flow; } int maxFlow() { int flow = 0; while(bfs()){ memcpy(cur,hd,sizeof(int)*(T+1)); flow += aug(S,1<<30); } return flow; } inline int read() { int ret; char c; while(c = getchar(),c<'0'||c>'9'); ret = c-'0'; while(c = getchar(),c>='0'&&c<='9') ret = ret*10 + c-'0'; return ret; } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif int n, m; while(~scanf("%d%d",&n,&m)){ S = 0; T = n+1; memset(hd,0xff,sizeof(int)*(T+1)); ec = 0; for(int i = 1; i <= n; i++){ Add(i,T,read()); Add(S,i,read()); } for(int i = 0; i < m; i++){ int a = read(),b = read(),w = read(); add(a,b,w); add(b,a,w); } printf("%d ",maxFlow()); } return 0; }