整理的算法模板合集: 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分数规划相关推荐

  1. SPFA-DFS P3385 模板 判断负环===vector为啥过不了?

    很蛋疼,用vector写了一遍只AC两个用例,其他WA,为啥呢?想不通啊...不应该啊 改成邻接表写,瞬间AC... 两者最多是个遍历顺序不同,存取效率不同,不至于WA啊,TLE还说的过去,有懂的指点 ...

  2. POJ 3259 Wormholes【最短路/SPFA判断负环模板】

    农夫约翰在探索他的许多农场,发现了一些惊人的虫洞.虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径 ...

  3. spfa 判断负环 (转载)

    当然,对于Spfa判负环,实际上还有优化:就是把判断单个点的入队次数大于n改为:如果总的点入队次数大于所有点两倍 时有负环,或者单个点的入队次数大于sqrt(点数)有负环.这样时间复杂度就降了很多了. ...

  4. Luogu P3385 【模板】负环 - 题解

    [模板]负环 题目描述 给定一个 nnn 个点的有向图,请求出图中是否存在从顶点 111 出发能到达的负环. 负环的定义是:一条边权之和为负数的回路. 输入格式 本题单测试点有多组测试数据. 输入的第 ...

  5. LightOJ - 1074 Extended Traffic(最短路+判断负环)

    题目链接:点击查看 题目大意:给出n个城市,每个城市都有一个拥挤度,从a到b的时间是(b的拥挤度-a的拥挤度)^3,点1为起点,求最短时间 题目分析:这个题第一感觉是个裸题,n还非常小,偷了个懒上了一 ...

  6. POJ - 3259 Wormholes(判断负环)

    题目链接:点击查看 题意:最短路判断负环 这里介绍三种方法判断负环,分别是spfa,bellman-ford和flyod算法,不过spfa的速度能比bellman-ford的速度慢了接近20倍是出乎 ...

  7. Wormholes——Bellman-Ford判断负环

    [题目描述] While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A w ...

  8. POJ3259(Wormholes) 判断负环

    题意: 农夫john发现了一些虫洞,虫洞是一种在你到达虫洞之前把你送回目的地的一种方式,FJ的每个农场,由n块土地(编号为1-n),M 条路,和W个 虫洞组成,FJ想从一块土地开始,经过若干条路和虫洞 ...

  9. UVA 558 SPFA 判断负环

    这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负 ...

最新文章

  1. 每日一皮:CPU的新用途,要不要试试?
  2. 数据库同步热备方案(云南某金属企业)
  3. 深入react技术栈(11):样式处理
  4. 【优化算法】蛙跳算法 (SFLA)【含Matlab源码 1839期】
  5. flask-script插件
  6. speex回声消除源码解读
  7. 远秋考试系统服务器网址,远秋医学在线考试系统
  8. CleanMyPC中文版切换教程(专注于电脑缓存文件清理的工具)
  9. 央行房贷新政带火北京学区房:相比前两月涨10%
  10. vue中的@click.native.prevent,点击事件加上native.prevent究竟有什么用呢?
  11. 蓝牙运动手环app开发方案
  12. 领导者应具备的三个能力
  13. 从STM32F407到AT32F407(一)
  14. VUE+Canvas实现简单的五子棋游戏
  15. 微信订阅号通过获取Openid并获取用户基本信息
  16. 魔兽世界怀旧版本最新服务器,魔兽世界怀旧服1.13.3版本更新了哪些 魔兽世界怀旧服1.13.3版本更新内容汇总...
  17. DRM驱动(一)之显示处理器介绍
  18. 定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!
  19. Activiti6自学之路(十)——编码实现请假审批流程(完整过程)
  20. 判断查找Cisco路由器故障方法汇总

热门文章

  1. 机器人视觉三维成像技术全解析
  2. python新手任务:python循环嵌套
  3. Oracle SQL Developer 的一个Bug
  4. checkstyle安装使用
  5. Linux之OpenSSL
  6. Linux运维人员成长之路学习书籍推荐
  7. stdio.h头文件中申明的基本函数
  8. ipv6改为ipv4
  9. 设置静态固定ip地址
  10. c语言程序与设计苏小红,c语言程序设计苏小红