UVALive 7264 Kejin Game (最大流最小割)
2017-07-23 21:06
811 查看
题意:有一个技能树,每个技能有一些“先修技能”,先修技能都得到后才可以得到当前技能。三种方法:1.逐个修技能,花费是技能的点值(数据中的倒数第二行)2.花费一些钱去掉某些边 (边权就是先修的条件) 3.跳过之前的条件直接得到某个技能,求得到某技能的最小花费
思路:经典建图。。建完图你会发现最小割就是要求的答案...
将每个点拆成 i 和 i',设一个源点与汇点。
1.对于边i--->j,连边i'--->j,容量为对应边的费用。
2.源点到 i 连边,容量为满足条件后购买 i 的费用。
3.对于 i 和 i' 连边,容量为直接购买 i 的费用。
4.对于目标点向汇点连边,容量为INF。
因为图中每个割为一种获得目标技能的方案,所以求最小割即可。
一开始知道最小割不就是一个原来联通图,通过去掉一些权值最小边, 变为不联通的图,这题怎么想也想不董根最小割啥关系啊,画了图知道了,这题是通过建边来将答案变成最小割(字比较难看QAQ
你会发现, 1234个割, 每个其实都是一种答案, 2把e点跟他相邻的三个技能点都取消了, 说明他没有前置技能点了,只需要加上平常的花费就好了, 1很简单, 就是从1到e挨个修炼,3,其实是把E的前置技能点全部买断了,再加上到E的花费, 4就是直接把E买断了...将E到t负值INF, 也就是最小割只能在前面的边出现...
总结下:
这题建图方式很强, 通过建图, 将问题转化为最小割问题,这也提示我们, 当有前置条件, 求最大最小的时候, 可能是网络流, 可能要转化成最小割, 这种建图方式要学一下,每个技能都直接练到源点, 单个技能肯定要拆点将它变成一个流, 这题,也许能出是通过画图看出来的, 以后不知道怎么建图,尝试画图,先把一些常规的画出来,往最小割拼拼....
代码:
思路:经典建图。。建完图你会发现最小割就是要求的答案...
将每个点拆成 i 和 i',设一个源点与汇点。
1.对于边i--->j,连边i'--->j,容量为对应边的费用。
2.源点到 i 连边,容量为满足条件后购买 i 的费用。
3.对于 i 和 i' 连边,容量为直接购买 i 的费用。
4.对于目标点向汇点连边,容量为INF。
因为图中每个割为一种获得目标技能的方案,所以求最小割即可。
一开始知道最小割不就是一个原来联通图,通过去掉一些权值最小边, 变为不联通的图,这题怎么想也想不董根最小割啥关系啊,画了图知道了,这题是通过建边来将答案变成最小割(字比较难看QAQ
你会发现, 1234个割, 每个其实都是一种答案, 2把e点跟他相邻的三个技能点都取消了, 说明他没有前置技能点了,只需要加上平常的花费就好了, 1很简单, 就是从1到e挨个修炼,3,其实是把E的前置技能点全部买断了,再加上到E的花费, 4就是直接把E买断了...将E到t负值INF, 也就是最小割只能在前面的边出现...
总结下:
这题建图方式很强, 通过建图, 将问题转化为最小割问题,这也提示我们, 当有前置条件, 求最大最小的时候, 可能是网络流, 可能要转化成最小割, 这种建图方式要学一下,每个技能都直接练到源点, 单个技能肯定要拆点将它变成一个流, 这题,也许能出是通过画图看出来的, 以后不知道怎么建图,尝试画图,先把一些常规的画出来,往最小割拼拼....
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 1e3+5; const int maxv = 1e5 + 5; int head[maxn], cur[maxn], d[maxn], s, t, k, sum; int n, m, g; struct node { int v, w, next; }edge[maxv]; void addEdge(int u, int v, int w) { edge[k].v = v; edge[k].w = w; edge[k].next = head[u]; head[u] = k++; edge[k].v = u; edge[k].w = 0; edge[k].next = head[v]; head[v] = k++; } int bfs() { memset(d, 0, sizeof(d)); d[s] = 1; queue<int> q; q.push(s); while(!q.empty()) { int u = q.front(); if(u == t) return 1; q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { int to = edge[i].v, w = edge[i].w; if(w && d[to] == 0) { d[to] = d[u] + 1; if(to == t) return 1; q.push(to); } } } return 0; } int dfs(int u, int maxflow) { if(u == t) return maxflow; int ret = 0; for(int i = cur[u]; i != -1; i = edge[i].next) { int to = edge[i].v, w = edge[i].w; if(w && d[to] == d[u]+1) { int f = dfs(to, min(maxflow-ret, w)); edge[i].w -= f; edge[i^1].w += f; ret += f; if(ret == maxflow) return ret; } } return ret; } int Dinic() { int ans = 0; while(bfs() == 1) { memcpy(cur, head, sizeof(head)); ans += dfs(s, INF); } return ans; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &m, &g); s = 0, t = n*2+1, k = 0; memset(head, -1, sizeof(head)); int x, y, z; for(int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &y, &z); addEdge(n+x, y, z); } for(int i = 1; i <= n; i++) { scanf("%d", &x); addEdge(s, i, x); } for(int i = 1; i <= n; i++) { scanf("%d", &x); addEdge(i, i+n, x); } addEdge(g+n, t, INF); printf("%d\n", Dinic()); } return 0; }
相关文章推荐
- [UVALive 7264] Kejin Game(最小割)
- UVa live6492Welcome Party(二分最大匹配之最小点覆盖)
- Kejin Game UVALive - 7264 拆点+最小割 15北京区域赛
- UVA Live 6474 Drop Zone 最小割=最大流
- UVALIVE 3661 Animal Run <最大-最小原理之一 最大流-最小割原理>
- Uvalive - 3026 Period (kmp求字符串的最小循环节+最大重复次数)
- Taxi Cab Scheme UVALive - 3126 最小路径覆盖解法(必须是DAG,有向无环图) = 结点数-最大匹配
- Kejin Game UVALive - 7264 拆点+最小割
- Error Curves(三分)uvalive 5009 求下凸 (最大值的最小值)
- UVALive 7264 (最小割)
- UVALIVE 4970 最小权匹配
- UVA 11297 Census(2D线段树解决子矩阵的最大最小)
- UVALive - 3971 组装电脑(最大值极小化)
- UVALive 3415 浅谈二分图最大点独立集架构建模
- uva 10099 - The Tourist Guide(最大生成树, 最小边最大)
- UVALive 4872 Underground Cables 最小生成树
- UVaLive/LA 6807 Túnel de Rata(最大生成树)
- UVA 11243 Texas Trip <三分 + 最大中求最小>
- 二分图最大匹配与最小顶点覆盖(教程系列)uva11419——我目前关于最大匹配最清晰的解释。
- UVA 1331 Minimax Triangulation 最大面积最小的三角剖分(区间dp--记忆化搜索)