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;
}

posted @ 2019-04-05 21:24  CaptainLi  阅读(155)  评论(0编辑  收藏  举报