1. 程式人生 > >HNOI2009 最小圈

HNOI2009 最小圈

++ 二分答案 分數 bool 答案 ref can rom href

傳送門

省選之前再水一發

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

HNOI2009 最小圈