SPFA模板+dfs版检测负环
const int MAXN=1e4+10;
int m,n,s,cnt,head[MAXN],dist[MAXN];
struct Edge {
int to,val,next;
} e[500010];
inline void add(int x,int y,int val) {
e[++cnt].to=y;
e[cnt].val=val;
e[cnt].next=head[x];
head[x]=cnt;
}
bool inque[MAXN];
queue<int>que;
inline bool SPFA() {
memset(dist,0x3f3f3f3f,sizeof(dist));
memset(inque,0,sizeof(inque));
dist[s]=0;
inque[s]=1;
que.push(s);
while(!que.empty()) {
int x=que.front();
que.pop();
inque[x]=0;
for(int i=head[x]; i; i=e[i].next) {
int y=e[i].to;
if(e[i].val+dist[x]<dist[y]) {
dist[y]=e[i].val+dist[x];
if(!inque[y]) {
inque[y]=1;
que.push(y);
}
}
}
}
return 1;
}
int main() {
read(n),read(m),read(s);
int x,y,val;
while(m--) {
read(x),read(y),read(val);
add(x,y,val);
}
SPFA();
for(int i=1; i<=n; ++i) {
if(dist[i]!=0x3f3f3f3f)
printf("%d ",dist[i]);
else
printf("2147483647 ");
}
return 0;
}
检测负环(dfs dpfa)
题目链接
题意 给定一张图,每个顶点有一个快乐值,每条边有一个长度,选择一个环使得总快乐值/总长最大。
输入
5 7
30
10
10
5
10
1 2 3
2 3 2
3 4 5
3 5 2
4 5 5
5 1 3
5 2 2
输出:
6.00
二分答案
更改边的权重\(w[i]\)=目标节点快乐值\(-\)边长*可能的答案,如果出现正环,则有答案,且该可能的答案太小了即,将\(-w\)作为真正的权值,检测是否有负环。
#include<bits/stdc++.h>
#include<queue>
#include<iostream>
#include<cstring>
using namespace std;
char buf[1<<17],*L=buf,*R=buf;
inline char gc() {
return L==R&&(R=(L=buf)+fread(buf,1,1<<17,stdin),L==R)?EOF:*L++;
}
template<typename T>
inline void read(T&x) {
int flag=x=0;
char ch=gc();
while (ch<'0'||ch>'9')
flag|=ch=='-',ch=gc();
while (ch>='0'&&ch<='9')
x=(x<<3)+(x<<1)+ch-48,ch=gc();
if(flag)
x=-x;
}
#define Memset(arr,val) memset(arr,val,sizeof(arr))
const int MAXN=1e4+10;
int k[MAXN],cnt,head[MAXN];
int n,m;
struct edge {
int to,len,next;
} e[MAXN*5];
inline void add(int x,int y,int len) {
e[++cnt].len=len;
e[cnt].next=head[x];
e[cnt].to=y;
head[x]=cnt;
}
double dis[MAXN],w[MAXN];
bool vis[MAXN];
int num[MAXN];
inline bool spfa(int x) {
vis[x]=1;
for(int i=head[x]; i; i=e[i].next) {
int y=e[i].to;
if(dis[y]>dis[x]-w[i]) {
dis[y]=dis[x]-w[i];
if(vis[y]||spfa(y)) {
vis[y]=0;
return 1;
}
}
}
return vis[x]=0;
}
inline bool check() {
Memset(dis,0);//因为不是求距离,所以随便初始化就ok了
Memset(vis,0);
for(int i=1; i<=n; ++i)
if(spfa(i))
return 1;
return 0;
}
int main() {
read(n),read(m);
for(int i=1; i<=n; ++i)
read(k[i]);
int x,y,len;
while(m--) {
read(x),read(y),read(len);
add(x,y,len);
}
double l=1,r=1001;
while(l+1e-5<r) {
double mid=(r+l)/2;
for(int i=1;i<=cnt;++i)w[i]=1.0*k[e[i].to]-e[i].len*mid;
if(check())
l=mid+1e-5;
else
r=mid-1e-5;
}
printf("%.2lf",r);
return 0;
}