HNOI2009 最小圈
省选之前再水一发
当做01分数规划+spfa判负环的板子题。二分答案mid,之后每条边边权-mid,在上边判是否有负环即可。
这里没有使用入队n次的spfa判负环,用的是基于dfs的SPFA……我也不知道哪个更好其实……
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 10005;
const int N = 2000005;
const int INF = 0x3f3f3f3f;
const double eps = 1e-10;
int read()
{
int ans = 0,op = 1;char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
return ans * op;
}
struct edge
{
int next,to,from;
double v,c;
}e[M<<3];
int head[M],ecnt,n,m,x,y;
bool vis[M],flag;
double ans,z,dis[M];
void add(int x,int y,double z)
{
e[++ecnt] = {head[x],y,x,z};
head[x] = ecnt;
}
void spfa(int x,double cur)
{
vis[x] = 1;
for(int i = head[x];i;i = e[i].next)
{
double d = e[i].v - cur;
if(dis[e[i].to] > dis[x] + d)
{
if(vis[e[i].to] || flag) {flag = 1;break;}
dis[e[i].to] = dis[x] + d,spfa(e[i].to,cur);
}
}
vis[x] = 0;
}
int main()
{
n = read(),m = read();
rep(i,1,m) x = read(),y = read(),scanf("%lf",&z),add(x,y,z);
double L = -1e6,R = 1e6;
while(R - L > eps)
{
double mid = (L+R) / 2.0;
memset(dis,0,sizeof(dis)),memset(vis,0,sizeof(vis)),flag = 0;
rep(i,1,n)
{
spfa(i,mid);
if(flag) break;
}
if(flag) R = mid;
else L = mid;
}
printf("%.8lf\n",L);
return 0;
}
当你意识到,每个上一秒都成为永恒。