URAL 1833|Hopes of Rowing|最小割

题目大意

现在有 n 个点,每个点需要给一个权值。有 m 条边,每条边需要满足两端点的权值和至少为 k,问一种权值方案使得所有点的权值和最小。

题解

其实这道题用 KM,用 Hungary 都能做。这里只提提最小割的做法。

现在有一个结论:每个点的权值只有 3 种取值: 0 , k 2 , k 0,\frac{k}{2},k 0,2k,k。显然如果某个点的相邻的点很多,而且至少有 2 个这中没有其他的相邻点的点(像菊花图),那么当前这个点的权值设为 k k k,其他设为 0 就是最好的,根据情况设为 k 2 \frac{k}{2} 2k

现在我们要决定每个点给哪种取值。我们要最小化总权值和,那么我们设计一个式子表示这个权值和:
min ⁡ { ∑ max ⁡ { 0 , x i } ⋅ 1 + ∑ max ⁡ { 0 , 1 − y i } ⋅ 1 + ∑ max ⁡ { 0 , y i − x j } ⋅ ∞ ( if adj(i,j) ) } \min\left\{\sum \max\{0,x_i\}\cdot 1+\sum \max\{0,1-y_i\}\cdot 1+\sum \max\{0,y_i-x_j\} \cdot \infin(\text{if adj(i,j)})\right\} min{max{0,xi}1+max{0,1yi}1+max{0,yixj}(if adj(i,j))}
其中 x i x_i xi 表示第 i i i 个人是否拿一份 k 2 \frac{k}{2} 2k元, x i = 1 x_i=1 xi=1 时拿; y i y_i yi 表示第 i i i 个人是否拿另一份 k 2 \frac{k}{2} 2k y i = 0 y_i=0 yi=0 时拿。那么这个式子中, ∑ max ⁡ { 0 , x i } ⋅ 1 \sum \max\{0,x_i\}\cdot 1 max{0,xi}1 表示让第 i i i 个人拿这个 k 2 \frac{k}{2} 2k元的成本为1(实际上权值和都是 k 2 \frac{k}{2} 2k的倍数,所以这里统一除 k 2 \frac{k}{2} 2k), ∑ max ⁡ { 0 , 1 − y i } ⋅ 1 \sum \max\{0,1-y_i\}\cdot 1 max{0,1yi}1 同理, ∑ max ⁡ { 0 , y i − x j } ⋅ ∞ ( if adj(i,j) ) \sum \max\{0,y_i-x_j\} \cdot \infin(\text{if adj(i,j)}) max{0,yixj}(if adj(i,j)) 表示如果 i i i j j j 相邻,那么两者的 y i = 1 y_i=1 yi=1 and x j = 0 x_j=0 xj=0 或者 y j = 1 y_j=1 yj=1 and x i = 0 x_i=0 xi=0 都是不可以的。
对于上面这个条件,我们首先知道这个:
x i + ( 1 − y i ) + x j + ( 1 − y j ) ≥ 2 x_i+(1-y_i)+x_j+(1-y_j) \geq 2 xi+(1yi)+xj+(1yj)2
表示一条边的两端点的总和至少为 k k k
然后我们得到: x i − y j ≥ y i − x j x_i-y_j\geq y_i-x_j xiyjyixj
那么这条式子不成立的必要条件是,左边为 -1,或者右边为 1,就是上面的两个条件。至于被多剪掉的情况(左边为 -1 右边为 -1,或者左边为 1 右边为 1)则没有关系,我们调整一下取值就可以得到同样的结果。

那么上面的这个就是最小割的式子。我们根据这个式子建图:

i 表示 x(i),i+n 表示 y(i)
s--1-->i
i+n--1-->t
i--inf-->j+n
j--inf-->i+n

那么流量就是总权值和除以 k 2 \frac{k}{2} 2k。然后我们找到 x i , y i x_i,y_i xi,yi的取值来输出答案。
怎么找 x i , y i x_i,y_i xi,yi 的权值呢?我们就要找割边。
找割边的方法是:从 s 出发遍历残余网络,设遍历到的集合为 vS, 从 t 走反向边 bfs一遍,设遍历到集合为vT, 若某条边(u, v) u∈vS, v∈vT,则这条边一定在最小割里。或者在残余网络中跑两次,从 s 能出发到达的 y i = 0 y_i=0 yi=0,接着从 t 出发不经过 s 出发经过的点到达的 x i = 1 x_i=1 xi=1

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
using namespace std;
const int N = 2555, M = 10000005, inf = 2147483647;
int h[N], p[M], v[M], w[M], edge = 1, s, t;
int level[N], cur[N], vis[N], q[N];
int vs[N], vt[N], cnt[N];
void add(int a, int b, int c) {
    p[++edge] = h[a]; v[edge] = b; w[edge] = c; h[a] = edge;
    p[++edge] = h[b]; v[edge] = a; w[edge] = 0; h[b] = edge;
}
bool bfs() {
    int i, x, f = 0, r = 0;
    FOR(i,s,t) level[i] = -1;
    q[r++] = s; level[s] = 0;
    while (f < r) {
        x = q[f++];
        for (i = h[x]; i; i = p[i])
            if (w[i] && level[v[i]] == -1) {
                level[v[i]] = level[x] + 1;
                q[r++] = v[i];
            }
    }
    return level[t] != -1;
}
int dfs(int x, int low) {
    int i, tmp, res = 0;
    if (x == t) return low;
    for (i = cur[x]; i && res < low; i = p[i])
        if (w[i] && level[v[i]] == level[x] + 1) {
            tmp = dfs(v[i], min(low - res, w[i]));
            w[i] -= tmp; w[i ^ 1] += tmp; res += tmp;
            if (w[i]) cur[x] = i;
        }
    if (!res) level[x] = -1;
    return res;
}
int dinic() {
    int ans = 0, i;
    while (bfs()) {
        FOR(i,s,t) cur[i] = h[i];
        ans += dfs(s, inf);
    }
    return ans;
}
void dfs(int *s, int x) {
    if (vis[x]) return;
    vis[x] = 1;
    s[x] = 1;
    for (int i = h[x]; i; i = p[i])
        if (w[i]) dfs(s, v[i]);
}
int main() {
    int n, m, k, i, x, y;
    scanf("%d%d%d", &n, &k, &m);
    s = 0; t = n + n + 1;
    FOR(i,1,n) add(s, i, 1), add(i + n, t, 1);
    FOR(i,1,m) {
    	scanf("%d%d", &x, &y);
    	add(x, y + n, 100);
    	add(y, x + n, 100);
    }
    dinic();
    memset(vis, 0, sizeof vis);
    dfs(vs, s);
    dfs(vt, t);
    FOR(i,n+1,2*n) cnt[i - n] += vs[i];
    FOR(i,1,n) cnt[i] += vt[i];
    FOR(i,1,n) printf("%.1f\n", cnt[i] * k / 2.0);
    return 0;
}

Hopes of Rowing

Description

On August 15, 2008, the rowers from Nizhny Tagil Mikhail Kuznetsov and Dmitry Larionov won a bronze Olympic medal in the men’s slalom canoe double event.
After that, the regional administration decided to support the Canoe Slalom School “Polyus” in Nizhny Tagil, where the athletes had trained. There were n young canoeists training at the school at that time. The principal of the school reported that m crews of tandem canoes had won national competitions in the years preceding the Olympics. Some of the athletes had won more than once as members of different crews. The principal asked the administration to pay the athletes bonuses so that the total bonus of each of the winning crews would be at least k roubles.
However, because of the financial crisis, officials from the Ministry for Physical Education and Sport tried to spend as little money as possible for granting the principal’s wish. What bonuses were paid to the young athletes?

Input

The first line contains the integers n, k, and m (2 ≤ n ≤ 500; 1 ≤ k ≤ 10000; 0 ≤ m ≤ 100000). In each of the following m lines you are given two different integers separated with a space. These are the numbers of athletes from one of the winning crews. The students of the school are numbered from 1 to n. Each winning crew enters the list only once.

Output

Output in the i-th line the amount of the bonus paid to the i-th athlete with an absolute error of at most 10 −6. If there are several answers, output any of them.

Sample Input

4 1000 4
1 2
1 3
2 4
3 4

Sample Output

146.5
853.5
853.5
146.5

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值