Kejin Game UVALive - 7264 拆点+最小割
2017-03-28 17:15
423 查看
传送门:UVALive - 7264
题意:给定一颗类似于dnf、lol点天赋时候的天赋(技能)树,技能获得的前提是他的前置技能都获得了,作为一个RMB玩家,你有特权:
1.直接花费一定数量的钱获得某个技能。
2.花费一定数量的钱将一个技能的某一个前置关系取消,即将前置技能到该技能的边消除(但不会获得该前置技能)。
如果正常学习技能的话每一个技能都要花费一定量的时间,问获得指定的技能的最少的花费是多少。
思路:读完提就会知道是图论相关,第一反应是最短路什么的,但是这些复杂的优先级关系并非最短路能处理的。后来看题解发现是拆点+最小割,其实就是最大流模板题,随便套个网络流算法的模板就能过,但是此题重点和难点在于如何建图。
假设要获得的技能为S。
1.将所有点拆成i和i'两个点,在建好的图中就用i和i+n分别表示。
2.若i->j有边(i为j的前置技能),则将i'到j建边,权值为用钱将该边消除的花费。
3.将源点和i建边,边权为正常学习该技能花费的时间(满足前置技能以后再学的花费)。
4.将i与i'建边,权值为用钱直接获得该点的花费(氪金,不用管前置技能)。
5.将S’与汇点建边,权值为inf。
这样最大流跑完了以后,S’与汇点之间正向边的流量就是源点与汇点的最小割,也是要求的最小花费。自己画个简单的图模拟一下很容易就明白为什么这样是对的,但是这种将题中不同条件转化为对应的边的思想是很难一天两天练成的,建图也是图论相关题的奥义所在。多刷题,少看题解,争取早日领略其中奥义,共勉。
代码:
isap是套的原来写好的板子。上面的子函数看似挺长好深奥的样子,实际上就是个模板,主函数中建边的过程才是网络流一类题目的难点。
题意:给定一颗类似于dnf、lol点天赋时候的天赋(技能)树,技能获得的前提是他的前置技能都获得了,作为一个RMB玩家,你有特权:
1.直接花费一定数量的钱获得某个技能。
2.花费一定数量的钱将一个技能的某一个前置关系取消,即将前置技能到该技能的边消除(但不会获得该前置技能)。
如果正常学习技能的话每一个技能都要花费一定量的时间,问获得指定的技能的最少的花费是多少。
思路:读完提就会知道是图论相关,第一反应是最短路什么的,但是这些复杂的优先级关系并非最短路能处理的。后来看题解发现是拆点+最小割,其实就是最大流模板题,随便套个网络流算法的模板就能过,但是此题重点和难点在于如何建图。
假设要获得的技能为S。
1.将所有点拆成i和i'两个点,在建好的图中就用i和i+n分别表示。
2.若i->j有边(i为j的前置技能),则将i'到j建边,权值为用钱将该边消除的花费。
3.将源点和i建边,边权为正常学习该技能花费的时间(满足前置技能以后再学的花费)。
4.将i与i'建边,权值为用钱直接获得该点的花费(氪金,不用管前置技能)。
5.将S’与汇点建边,权值为inf。
这样最大流跑完了以后,S’与汇点之间正向边的流量就是源点与汇点的最小割,也是要求的最小花费。自己画个简单的图模拟一下很容易就明白为什么这样是对的,但是这种将题中不同条件转化为对应的边的思想是很难一天两天练成的,建图也是图论相关题的奥义所在。多刷题,少看题解,争取早日领略其中奥义,共勉。
代码:
//ISAP int #include<bits/stdc++.h> #define ll long long #define MAXN 1010 #define inf 0x3f3f3f3f using namespace std; int n,m;//题目输入点数,边数 struct Edge{ int v,next; int cap,flow; }edge[MAXN*100]; int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN]; int cnt=0;//实际存储总边数 void init() { cnt=0; memset(pre,-1,sizeof(pre)); } void add(int u,int v,int w)//加边 { edge[cnt].v=v; edge[cnt].cap=w; edge[cnt].flow=0; edge[cnt].next=pre[u]; pre[u]=cnt++; } bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长 { memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=1; dep[t]=0; queue<int>q; while(!q.empty()) q.pop(); q.push(t);//从汇点开始反向建层次图 while(!q.empty()) { int u=q.front(); q.pop(); for(int i=pre[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量 { dep[v]=dep[u]+1; gap[dep[v]]++; q.push(v); //if(v==s)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定 //break; } } } return dep[s]!=-1; } int isap(int s,int t) { bfs(s,t); memcpy(cur,pre,sizeof(pre)); int u=s; path[u]=-1; int ans=0; while(dep[s]<n)//迭代寻找增广路 { if(u==t) { int f=inf; for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路 f=min(f,edge[i].cap-edge[i].flow); for(int i=path[u];i!=-1;i=path[edge[i^1].v]) { edge[i].flow+=f; edge[i^1].flow-=f; } ans+=f; u=s; continue; } bool flag=false; int v; for(int i=cur[u];i!=-1;i=edge[i].next) { v=edge[i].v; if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow) { cur[u]=path[v]=i;//当前弧优化 flag=true; break; } } if(flag) { u=v; continue; } int x=n; if(!(--gap[dep[u]]))return ans;//gap优化 for(int i=pre[u];i!=-1;i=edge[i].next) { if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x) { x=dep[edge[i].v]; cur[u]=i;//常数优化 } } dep[u]=x+1; gap[dep[u]]++; if(u!=s)//当前点没有增广路则后退一个点 u=edge[path[u]^1].v; } return ans; } int main() { //std::ios::sync_with_stdio(0); int T,s; cin>>T; while(T--) { init(); scanf("%d%d%d",&n,&m,&s); int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(a+n,b,c); add(b,a+n,0);//注意加反向边时一般初始流量为0! } for(int i=1;i<=n;i++) { scanf("%d",&a); add(0,i,a); add(i,0,0); } for(int i=1;i<=n;i++) { scanf("%d",&a); add(i,i+n,a); add(i+n,i,0); } add(s+n,2*n+1,inf); add(2*n+1,s+n,0); n=2*n+1; printf("%d\n",isap(0,n)); } return 0; }
isap是套的原来写好的板子。上面的子函数看似挺长好深奥的样子,实际上就是个模板,主函数中建边的过程才是网络流一类题目的难点。
相关文章推荐
- Kejin Game UVALive - 7264 拆点+最小割 15北京区域赛
- UVALive 7264 (最小割)
- [UVALive 7264] Kejin Game(最小割)
- UVALive 7264 Kejin Game (最大流最小割)
- UVALive - 4848 Tour Belt(暴力+最小生成树)
- UVaLive 4597 Inspection (网络流,最小流)
- UVALive 6837 (最小生成树)
- UVAlive 6199 不定根最小树形图
- 例题1.22 最大子矩阵 City Game UVALive - 3029 扫描法
- UVALive 3126 出租车(DAG的最小不相交路径覆盖)
- UVALive 2930 Minimizing Maximizer(最小区间覆盖数 DP + 线段树优化)
- UVALive 5099 Nubulsa Expo 全局最小割问题
- UVALive 7278 Game of Cards (sg函数)
- UVAlive 5027 card game KM
- UVALive 3661 Animal Run(最短路解最小割)
- UVALive 7303 Aquarium 最小生成树
- 【UVALive 7505】Hungry Game of Ants(DP)
- UVALive 3887 边权极差最小生成树模板
- UVALive - 7715 The 2016 ACM-ICPC Asia Jakarta Regional Contest E - Guessing Game 繁琐的等差数列求和
- 【UVALive】7502 Suffixes and Palindromes【根据sa数组以及回文半径数组构造字典序最小的串】