bzoj 1937 最小生成树【费用流】
2016-06-30 14:28
429 查看
题目大意:给定一张无向图和一颗生成树,求使这棵树变成最小生成树的最小代价
我们知道最优情况下如果要改变,树上边只会减小,非树边只会增大。对于每条非树边 j 两端点间的树边 i,就有 wj+dj>=wi−di,就是 di+dj>=wi−wj。
那么建图就是:
· S -> i (1,0)
· i -> j (1,wi−wj)
· j -> T (1,0)
然后跑最大费用流就好啦QAQ
我们知道最优情况下如果要改变,树上边只会减小,非树边只会增大。对于每条非树边 j 两端点间的树边 i,就有 wj+dj>=wi−di,就是 di+dj>=wi−wj。
那么建图就是:
· S -> i (1,0)
· i -> j (1,wi−wj)
· j -> T (1,0)
然后跑最大费用流就好啦QAQ
#include<iostream> #include<cstring> #include<cstdio> #define N 805 #define M 100000 #define INF 1000000000 using namespace std; int n,m,siz = 1,S,T; int a[55][55],b[55][55],id[55][55],fa[55],x ,y ; int first ,next[M],to[M],flow[M],cost[M]; int d ,p[M * 10],pre ; bool v ; void inser(int x,int y,int w,int c) { next[++ siz] = first[x]; first[x] = siz; to[siz] = y; flow[siz] = w; cost[siz] = c; } void add_edge(int x,int y,int w,int c) { inser(x,y,w,c),inser(y,x,0,-c); } bool spfa() { int head = 0,tail = 1; memset(d,192,sizeof(d)); memset(pre,0,sizeof(pre)); d[p[1] = S] = 0; while (head ^ tail) { int x = p[++ head]; v[x] = false; for (int i = first[x];i;i = next[i]) if (flow[i] && d[to[i]] < d[x] + cost[i]) { d[to[i]] = d[x] + cost[i]; pre[to[i]] = i; if (!v[to[i]]) v[p[++ tail] = to[i]] = true; } } return d[T] ^ d[0]; } int mcmf() { int ret = 0; while (spfa() && d[T] > 0) { int w = INF; for (int i = pre[T];i;i = pre[to[i ^ 1]]) w = min(w,flow[i]); for (int i = pre[T];i;i = pre[to[i ^ 1]]) flow[i] -= w,flow[i ^ 1] += w; ret += d[T] * w; } return ret; } void dfs(int x) { for (int y = 1;y <= n;y ++) if (b[x][y] && y != fa[x]) fa[y] = x,dfs(y); } int main() { scanf("%d%d",&n,&m); for (int i = 1;i <= m;i ++) { scanf("%d%d",&x[i],&y[i]);scanf("%d",&a[x[i]][y[i]]); a[y[i]][x[i]] = a[x[i]][y[i]]; id[x[i]][y[i]] = id[y[i]][x[i]] = i; } for (int u,v,i = 1;i < n;i ++) { scanf("%d%d",&u,&v); b[u][v] = b[v][u] = a[u][v]; a[u][v] = a[v][u] = 0; } for (int i = 1;i <= m;i ++) if (a[x[i]][y[i]]) { int u = x[i],v = y[i],w = a[u][v]; fa[v] = 0,dfs(v); for (int z = u;z ^ v;z = fa[z]) if (b[z][fa[z]] > w) add_edge(id[z][fa[z]],i,1,b[z][fa[z]] - w); } S = m+1,T = S+1; for (int i = 1;i <= m;i ++) b[x[i]][y[i]] ? add_edge(S,i,1,0) : add_edge(i,T,1,0); cout << mcmf() << endl; return 0; }
相关文章推荐
- webstorm12破解方法
- Linux Vsftpd 连接超时解决方法
- 响应式 Web
- nginx root alias 区别
- ImageView 自定义
- 如何创建CocoaPods以及存在的问题
- Xcode找不到模拟器出现"My Mac"
- mysql事务和锁InnoDB
- 偏好设置保存账号密码
- LeetCode Reverse Vowels of a String(字符串中元音字符反转)
- UITabBarController作为根视图控制器的时候出现的问题,popToRootViewController的时候出现两个TabBar
- Sendmail 设置为本地SMTP服务器给客户端发送邮件
- AndroidStudio 更新失败,sdk更新失败。http://www.android-studio.org/ 下载AS安装包 跳转到Google,无法下载
- MySQL慢查询可视化(1):pt-query-digest + Anemometer
- 175-178
- const T vs. T const ——Dan Saks 【翻译】
- 如何向线程函数传递多个参数?
- 理解inode
- 点击按钮改变本身按钮的文字内容
- mysql进阶:group_concat使用例子