模板 - 判断负环(超时高效优化技巧)、01分数规划
整理的算法模板合集: ACM模板
判断负环
判正环求最长路,判负环求最短路
int n; // 总点数
int h[N], w[N], e[N], ne[N], idx; // 邻接表存储所有边
int dist[N], cnt[N]; // dist[x]存储1号点到x的最短距离,cnt[x]存储1到x的最短路中经过的点数
bool st[N]; // 存储每个点是否在队列中// 如果存在负环,则返回true,否则返回false
bool spfa()
{// 原理:如果某条最短路径上有n个点(除了自环),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。memset(dis,0,sizeof dis);//如果求正环,则初始化为负无穷memset(st,false,sizeof st);memset(cnt,0,sizeof cnt);queue<int> q;for(int i=0;i<=n;i++) q.puh(i),st[i]=true;//如果有虚拟超级源点和所有的点相连,那么只需加入源点即可int count=0;while(q.size()){int t=q.front();st[t]=false;q.pop();for(int i=h[t];i!=-1;i=ne[i]){int j=e[i];if(dis[j]>dis[t]+w[i]){dis[j]=dis[t]+w[i];cnt[j]=cnt[t]+1;//if(++cont>4*N) return true; 当点的更新次数大于总点数的2~5倍时,就可认为存在环if(cnt[j]>=n) return true;if(!st[j]){q.push(j);st[j]=true;}}}}return false;
}
01分数规划
01分数规划问题可以用二分+负/正环判断解决。
我们要求的是平均长度,也就是每一条字符串的长度之和除以总的字符串个数,换成数学公式即为下式(个数对于每一个字符串来说都是1):∑wi∑1\frac{\sum w_i}{\sum 1}∑1∑wi
要求这个值最大,满足单调性,很明显是一个01分数规划问题,自然使用二分答案。我们设答案为mid
那么如果当前答案不够需要更大,上式即为∑wi∑1>mid\frac{\sum w_i}{\sum 1}>mid∑1∑wi>mid化简以后:
∑wi>mid∗∑1\sum w_i>mid * \sum 1∑wi>mid∗∑1
∑wi>∑mid\sum w_i>\sum mid∑wi>∑mid
∑wi−∑mid>0\sum w_i - \sum mid > 0∑wi−∑mid>0
那么也就是说对于每一个边,给它赋权值wi−midw_i - midwi−mid,如果存在正环,也就意味着有一个环的权值和大于0,也就是∑wi−∑mid>0\sum w_i - \sum mid > 0∑wi−∑mid>0,就意味着mid
需要更大。
这里可以直接用权值建图,然后直接跑spfa,把不同的mid放到更新最短路时减去,因为每次只是-mid,与其他的任何条件都没有关系,只需要建一次图,如果权值经过化简得到的是wi−xi∗midw_i - x_i* midwi−xi∗mid之类的就需要每次二分对mid
进行check
的时候,check
函数里都新建一张权值为wi−xi∗midw_i - x_i* midwi−xi∗mid来判定是否有正/负环。具体代码在下面
判负环时TLE的优化技巧:
- 经验优化(如果总的入队次数超过一个挺大的值,我们根据经验判断一定存在负环才会导致运行时间慢,直接判定是负环,有WA的风险)
- 使用stack(能有效优化负环超时的问题,有TLE的风险)
经验trick
一般总入队次数超过总边数的2~5倍或者边数较小次数大于1e6即可判定为负环,但是会有WA的风险。
const int N = 1000, M = 500007, INF = 0x3f3f3f3f;
double eps = 1e-4;int ver[M],nex[M],edge[M],head[N],tot = 1;
int n;//这里的n是字符的个数
int m;
int q[N],cnt[N],vis[N];
double dist[N];void add(int x,int y,int z){ver[++tot] = y;edge[tot] = z;nex[tot] =head[x];head[x] = tot;
}bool spfa(double mid){memset(cnt,0,sizeof cnt);memset(vis,0,sizeof vis);int hh = 0,tt = 0;for(int i = 0;i < 676;++i){q[tt ++ ] = i;vis[i] = true;}int counts = 0;//经验优化while(hh != tt){int x = q[hh ++ ];if(hh == N)hh = 0;vis[x] = false;for(int i = head[x];~i;i = nex[i]){int y = ver[i],z = edge[i];if(dist[y] < dist[x] + z - mid){dist[y] = dist[x] + z - mid;cnt[y] = cnt[x] + 1;counts ++ ;if(counts > 10000)return true;if(cnt[y] >= N)return true;if(!vis[y]){vis[y] = true;q[tt ++ ] = y;if(tt == N)tt = 0;}}}}return false;
}int main(){while(scanf("%d",&n) && n){memset(head,-1,sizeof head);tot = 1;for(int i = 1;i <= n;++i){char s[1010];scanf("%s",s);int len = strlen(s);if(len < 2)continue;int a = (s[0] - 'a' )* 26 + s[1] - 'a';int b = (s[len - 2] - 'a') * 26 + s[len - 1] - 'a';add(a,b,len);}if(!check(0))puts("No solution");else {double l = 0,r = 1000;while(r - l > eps){double mid = (l + r) / 2;if(spfa(mid))l = mid;else r = mid;}printf("%lf\n",r);}}return 0;
}
使用stack
注意,stack
只有在判断负环的情况下会有高效的优化作用,一般的spfa中队列比栈的性能更佳
bool spfa(double mid){memset(cnt,0,sizeof cnt);memset(vis,0,sizeof vis);int hh = 0,tt = 0;for(int i = 0;i < 676;++i){q[tt ++ ] = i;vis[i] = true;}int counts = 0;//经验优化while(hh != tt){int x = q[-- tt];vis[x] = false;for(int i = head[x];~i;i = nex[i]){int y = ver[i],z = edge[i];if(dist[y] < dist[x] + z - mid){dist[y] = dist[x] + z - mid;cnt[y] = cnt[x] + 1;if(cnt[y] >= N)return true;if(!vis[y]){vis[y] = true;q[tt ++ ] = y;}}}}return false;
}
模板 - 判断负环(超时高效优化技巧)、01分数规划相关推荐
- SPFA-DFS P3385 模板 判断负环===vector为啥过不了?
很蛋疼,用vector写了一遍只AC两个用例,其他WA,为啥呢?想不通啊...不应该啊 改成邻接表写,瞬间AC... 两者最多是个遍历顺序不同,存取效率不同,不至于WA啊,TLE还说的过去,有懂的指点 ...
- POJ 3259 Wormholes【最短路/SPFA判断负环模板】
农夫约翰在探索他的许多农场,发现了一些惊人的虫洞.虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径 ...
- spfa 判断负环 (转载)
当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍 时有负环,或者单个点的入队次数大于sqrt(点数)有负环.这样时间复杂度就降了很多了. ...
- Luogu P3385 【模板】负环 - 题解
[模板]负环 题目描述 给定一个 nnn 个点的有向图,请求出图中是否存在从顶点 111 出发能到达的负环. 负环的定义是:一条边权之和为负数的回路. 输入格式 本题单测试点有多组测试数据. 输入的第 ...
- LightOJ - 1074 Extended Traffic(最短路+判断负环)
题目链接:点击查看 题目大意:给出n个城市,每个城市都有一个拥挤度,从a到b的时间是(b的拥挤度-a的拥挤度)^3,点1为起点,求最短时间 题目分析:这个题第一感觉是个裸题,n还非常小,偷了个懒上了一 ...
- POJ - 3259 Wormholes(判断负环)
题目链接:点击查看 题意:最短路判断负环 这里介绍三种方法判断负环,分别是spfa,bellman-ford和flyod算法,不过spfa的速度能比bellman-ford的速度慢了接近20倍是出乎 ...
- Wormholes——Bellman-Ford判断负环
[题目描述] While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A w ...
- POJ3259(Wormholes) 判断负环
题意: 农夫john发现了一些虫洞,虫洞是一种在你到达虫洞之前把你送回目的地的一种方式,FJ的每个农场,由n块土地(编号为1-n),M 条路,和W个 虫洞组成,FJ想从一块土地开始,经过若干条路和虫洞 ...
- UVA 558 SPFA 判断负环
这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负 ...
最新文章
- 每日一皮:CPU的新用途,要不要试试?
- 数据库同步热备方案(云南某金属企业)
- 深入react技术栈(11):样式处理
- 【优化算法】蛙跳算法 (SFLA)【含Matlab源码 1839期】
- flask-script插件
- speex回声消除源码解读
- 远秋考试系统服务器网址,远秋医学在线考试系统
- CleanMyPC中文版切换教程(专注于电脑缓存文件清理的工具)
- 央行房贷新政带火北京学区房:相比前两月涨10%
- vue中的@click.native.prevent,点击事件加上native.prevent究竟有什么用呢?
- 蓝牙运动手环app开发方案
- 领导者应具备的三个能力
- 从STM32F407到AT32F407(一)
- VUE+Canvas实现简单的五子棋游戏
- 微信订阅号通过获取Openid并获取用户基本信息
- 魔兽世界怀旧版本最新服务器,魔兽世界怀旧服1.13.3版本更新了哪些 魔兽世界怀旧服1.13.3版本更新内容汇总...
- DRM驱动(一)之显示处理器介绍
- 定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!
- Activiti6自学之路(十)——编码实现请假审批流程(完整过程)
- 判断查找Cisco路由器故障方法汇总