bzoj1497 最大获利(最大权闭合子图)
程序员文章站
2022-05-17 16:08:00
思路
对于每个中转站向T连一条权值为建这个中转站代价的边。割掉这条边表示会建这个中转站。
对于每个人向他的两个中转站连一条权值为$INF$的边。割掉这条边表示不要这个收益。 ......
思路
对于每个中转站向\(t\)连一条权值为建这个中转站代价的边。割掉这条边表示会建这个中转站。
对于每个人向他的两个中转站连一条权值为\(inf\)的边。然后从\(s\)向这个人连一条权值为这个人的收益的边,割掉这条边表示不要这个收益。
这就是最大权闭合子图的模型。
最后的答案=全部的收益-割掉的收益-建中转站的代价=全部收益-最小割
代码
#include<cstring> #include<algorithm> #include<queue> #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<ctime> #include<bitset> using namespace std; typedef long long ll; const int n = 100010,m = 1000010,inf = 1e9; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } struct node { int v,nxt,w; }e[m << 1]; int head[n],ejs = 1; void add(int u,int v,int w) { e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w; e[++ejs].v = u;e[ejs].nxt = head[v];head[v] = ejs;e[ejs].w = 0; } int s,t; int n,m,cur[n]; queue<int>q; int dep[n]; int bfs() { while(!q.empty()) q.pop(); memset(dep,0,sizeof(dep)); dep[s] = 1;q.push(s); while(!q.empty()) { int u = q.front();q.pop(); for(int i = head[u];i;i = e[i].nxt) { int v = e[i].v; if(!dep[v] && e[i].w) { dep[v] = dep[u] + 1;q.push(v); if(v == t) return 1; } } } return 0; } int dfs(int u,int now) { if(u == t) return now; int ret = 0; for(int &i = cur[u];i;i = e[i].nxt) { int v = e[i].v; if(dep[v] == dep[u] + 1 && e[i].w) { int k = dfs(v,min(now - ret,e[i].w)); ret += k; e[i].w -= k; e[i ^ 1].w += k; if(ret == now) return ret; } } return ret; } int dinic() { int ans = 0; while(bfs()) { for(int i = 1;i <= t;++i) cur[i] = head[i]; ans += dfs(s,inf); } return ans; } int main() { n = read(),m = read(); t = n + m + 2,s = t - 1; int tot = 0; for(int i = 1;i <= n;++i) { int w = read(); add(i,t,w); } for(int i = 1;i <= m;++i) { int x = read(),y = read(),w = read(); add(i + n,x,inf);add(i + n,y,inf); add(s,i + n,w); tot += w; } cout<<tot - dinic(); return 0; }
上一篇: Java常用API及Math类
下一篇: 可以执行系统命令的ASP原码放送