[洛谷P3288][SCOI2014][BZOJ3597]方伯伯运椰子

Address

Solution

  • c i c_i ci 看作边 ( u i , v i ) (u_i,v_i) (ui,vi) 的流量,并将每条边的容量都看作 ∞ ∞
  • a i a_i ai 看作把边 ( u i , v i ) (u_i,v_i) (ui,vi) 增广 1 1 1 单位流量的花费, b i b_i bi 看作将 ( u i , v i ) (u_i,v_i) (ui,vi) 退 1 1 1 单位流量的花费,也就是把边 ( v i , u i ) (v_i,u_i) (vi,ui) 增广 1 1 1 单位流量的花费。
  • d i d_i di 看作把边 ( u i , v i ) (u_i,v_i) (ui,vi) 增广 1 1 1 单位流量的代价,同时也看作把边 ( v i , u i ) (v_i,u_i) (vi,ui) 增广 1 1 1 单位流量的收益
  • r e s = X − Y res=X-Y res=XY,显然 ⌊ \lfloor ( u i , v i ) (u_i,v_i) (ui,vi) 增广 1 1 1 单位流量 ⌋ \rfloor r e s res res 的贡献是 − b i − d i -b_i-d_i bidi ⌊ \lfloor ( v i , u i ) (v_i,u_i) (vi,ui) 增广 1 1 1 单位流量 ⌋ \rfloor r e s res res 的贡献是 d i − a i d_i-a_i diai
  • 注意 c i = 0 c_i=0 ci=0 时,不能增广 ( v i , u i ) (v_i,u_i) (vi,ui)
  • 先按上面所说的建好一张新图。
  • 题目要求流量不能变少,又因为流量变多肯定不优,所以我们要让流量不变。
  • 也就是说我们要增广一些环。
  • 看到 ( X − Y ) / k (X-Y)/k (XY)/k,显然的分数规划模型。
  • 二分答案,判断是否 r e s / k ≥ m i d res/k≥mid res/kmid,即是否 r e s − m i d ∗ k ≥ 0 res-mid*k≥0 resmidk0
  • 考虑将新图上的每条边减去 m i d mid mid,然后如果图上存在一个环使得边权和非负,那么 r e s / k ≥ m i d res/k≥mid res/kmid

Code

#include <bits/stdc++.h>

using namespace std;

template <class t>
inline void read(t & res)
{
   char ch;
   while (ch = getchar(), !isdigit(ch));
   res = ch ^ 48;
   while (ch = getchar(), isdigit(ch))
   res = res * 10 + (ch ^ 48);
}

const int e = 1e5 + 5;
const double inf = 1e18, eps = 1e-4;
int n, m, adj[e], nxt[e], go[e], num, s, cnt[e];
double len[e], ans, dis[e];
bool vis[e];

inline void add(int x, int y, double v)
{
   nxt[++num] = adj[x]; adj[x] = num; go[num] = y; len[num] = v;
}

inline bool check(double mid)
{
   queue<int>q;
   int i;
   for (i = 1; i <= n + 2; i++) vis[i] = 1, dis[i] = 0, cnt[i] = 1, q.push(i);
   while (!q.empty())
   {
   	int u = q.front();
   	q.pop();
   	vis[u] = 0;
   	for (i = adj[u]; i; i = nxt[i])
   	{
   		int v = go[i];
   		if (dis[u] + len[i] - mid >= dis[v])
   		{
   			dis[v] = dis[u] + len[i] - mid;
   			cnt[v] = cnt[u] + 1;
   			if (cnt[v] >= n + 2) return 1;
   			if (!vis[v]) q.push(v), vis[v] = 1;
   		}
   	}
   }
   return 0;
}

int main()
{
   int i, u, v, ai, bi, ci, di;
   read(n); read(m); m--;
   while (m--)
   {
   	read(u); read(v); read(ai); read(bi); read(ci); read(di);
   	add(u, v, -bi - di);
   	if (ci) add(v, u, di - ai);
   }
   read(u); read(s); read(ai); read(bi); read(ci); read(di);
   double l = 0, r = 1e9;
   while (r - l > eps)
   {
   	double mid = (l + r) / 2.0;
   	if (check(mid)) ans = l = mid;
   	else r = mid;
   }
   printf("%.2lf\n", ans);
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值