P3199 【[HNOI2009]最小圈】

疑似三倍经验

因为和机房一些大佬一起做的这道题,所以emmm他们貌似也写了题解,在做这道题的时候也参照了其他大佬写的一些题解,所以如果程序有雷同请见谅(手动鞠躬)


题目也是莫名其妙地给了一大串数学式,简洁地重新说一下题目

给你一张图,图中有环,定义一个环的平均值为环的边权和÷环中点的个数,那么就应该有了一中非常暴力的思路

  • 想办法找出来图中所有的环并求出其平均值,再比较出最小值

这个方法确实怎么想都很暴力,但是一点也不好实现,可能是我太弱,我实在想不太出来有什么算法可以找出来所有的环,所以这种思路先给我PASS掉

而正解呢?应该是二分答案。为什么?

  • 既然我们找不出来环,我们逆向思维,直接枚举平均值,看是否会有一个环符合条件,那么这道题就变成了:二分枚举平均值,找到是否有环符合条件

若我们此时枚举的平均值为 a n s ans ans,有 k k k个字符串,那么就有

a n s ∗ k = l e n 1 + l e n 2 + l e n 3 + . . . + l e n k ans * k = len1 + len2 + len3 + ... + lenk ans∗k=len1+len2+len3+...+lenk

那道这个式子之后,我们对它进行移项

0 = l e n 1 − a n s + l e n 2 − a n s + l e n 3 − a n s + . . . + l e n k − a n s 0=len1-ans+len2-ans+len3-ans+...+lenk-ans 0=len1−ans+len2−ans+len3−ans+...+lenk−ans

那么对于满足以下式子,就可以判断是环了,所以在跑 S P F A SPFA SPFA更新距离的时候,就应该像下面这样

0 ≤ l e n 1 − a n s + l e n 2 − a n s + l e n 3 − a n s + . . . + l e n k − a n s 0 \leq len1-ans+len2-ans+len3-ans+...+lenk-ans 0≤len1−ans+len2−ans+len3−ans+...+lenk−ans

所以这里就直接给程序了(三道题的)

SP2885 WORDRING - Word Rings

P3199 HNOI2009最小圈

复制代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=30000000+51;
const double INF=(1e5)*1.0;
const double eqs=1e-9;
int n,m;
struct node {
	int net,to;
	double z;
} e[MAXN];
int head[MAXN],tot;
void add(int x,int y,double z) {
	e[++tot].net=head[x];
	e[tot].to=y;
	e[tot].z=z;
	head[x]=tot;
}

double d[MAXN];
bool v[MAXN],flag;
bool spfa(int x,double k) {
	v[x]=true;
	for(register int i=head[x]; i; i=e[i].net) {
		int y=e[i].to;
		double z=e[i].z;
		if(d[y]>d[x]+z-k) {
			d[y]=d[x]+z-k;
			if(v[y]==true||spfa(y,k)==true) return true;
		}
	}
	v[x]=false;
	return false;
}
bool check(double x) {
	for(register int i=1; i<=n; i++) {
		d[i]=20040915;
		v[i]=false;
	}
	for(register int i=1; i<=n; i++) {
		if(spfa(i,x)==true) return true;
	}
	return false;
}
int main() {
	scanf("%d%d",&n,&m);
	for(register int i=1; i<=m; i++) {
		int x,y;
		double z;
		scanf("%d%d%lf",&x,&y,&z);
		add(x,y,z);
	}
	double l=-INF,r=INF;
	while(r-l>eqs) {
		double mid=(l+r)/2;
		if(check(mid)==true) r=mid;
		else l=mid;
	}
	printf("%.8lf",l);
	return 0;
}

UVA11090 Going in Cycle!!

复制代码
#include <bits/stdc++.h>
using namespace std;
int T,n,m,u,v,w,tot;
double dis[520010];
int vis[520010],head[520010];

struct node {
	int to,net;
	double val;
} e[520010];

inline void add(int u,int v,double w) {
	e[++tot].to=v;
	e[tot].val=w;
	e[tot].net=head[u];
	head[u]=tot;
}

inline bool dfs(int now,double x) {
	vis[now]=1;
	for(register int i=head[now];i;i=e[i].net) {
		int v=e[i].to;
		if(dis[v]>dis[now]+e[i].val-x) {
			dis[v]=dis[now]+e[i].val-x;
			if(vis[v]==1||dfs(v,x)==true) return true;
		}
	}
	vis[now]=0;
	return false;
}

inline bool check(double x) {
	for(register int i=1;i<=n;i++) {
		vis[i]=0;
		dis[i]=20050206;
	}
	for(register int i=1;i<=n;i++) {
		if(dfs(i,x)==true) return true;
	}
	return false;
}

int main() {
	scanf("%d",&T);
	for(register int k=1;k<=T;k++) {
		tot=0;
		for(register int i=1;i<=n;i++) head[i]=0;
		scanf("%d%d",&n,&m);
		for(register int i=1;i<=m;i++) {
			scanf("%d%d%d",&u,&v,&w);
			add(u,v,w);
		}
		double l=-10000000,r=10000000;
		while(r-l>1e-10) {
			double mid=(l+r)/2;
			if(check(mid)==true) r=mid;
			else l=mid;
		}
		printf("Case #%d: ",k);
		if(l==10000000) puts("No cycle found.");
		else printf("%.2lf\n",l);
	}
	return 0;
}
相关推荐
黄敬峰1 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术2 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六5 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术6 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize7 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考20 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
CSharp精选营1 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
To_OC2 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode