非完整版翻译:
给出一棵树与一些其他边,我们对每条边的花费定义为改变后的权值与原来权值之差的绝对值,我们要求以最小的总花费来保证这棵树是最小生成树。输出改变后每条边的权值。总点数
N<=60
,总边数
M<=400
,边权
ci<=10000
。
题解:
乍一看,不怎么会做;再一看,还是不会做,只能参考题解了…
对于每条不属于树的边,加上它后必定会形成一个环,如果原来的tree边要在最小生成树中,那么必须满足
w[i]−x[i]<=w[j]+x[j]
(
x[k]
表示第k条边的改变量,
w[k]
表示第k条边的原始权值,且
i<n
&&
j>=n
)。变形一下,可以发现
x[i]+x[j]>=w[i]−w[j]
。
是不是很像KM中的顶标?
没错,就是它。想到这里恭喜你就要做出这题了O(∩_∩)O~
我们对于
i
与
#include <cstdio>
#include <cstring>
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MIN(a, b) ((a)<(b)?(a):(b))
using namespace std;
const int MAXN = 69;
const int MAXM = 409;
const int INF = 0x3f3f3f3f;
int n, m;
struct Edge
{
int v, w, ne;
}e[MAXN<<1];
int head[MAXN], p;
int tree_w[MAXN], else_w[MAXM];
int g[MAXM][MAXM];
inline void add(int u, int v, int w)
{
e[p].v = v;e[p].w = w;
e[p].ne = head[u];
head[u] = p++;
}
inline bool dfs(int cnt, int end, int fa, int val, int id)
{
if(cnt == end) return true;
for(int i = head[cnt]; i != -1; i = e[i].ne)
{
int to = e[i].v;
if(to != fa && dfs(to, end, cnt, val, id))
{
g[i>>1][id] = MAX(g[i>>1][id], e[i].w-val);
return true;
}
}
return false;
}
inline void init()
{
scanf("%d%d", &n, &m);
memset(head, -1, n*sizeof(int));
for(int i = 0; i < n-1; ++i)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
u--, v--;
add(u, v, w);add(v, u, w);
tree_w[i] = w;
}
m -= n-1;
for(int i = 0; i < m; ++i)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
u--, v--;
dfs(u, v, -1, w, i);
else_w[i] = w;
}
}
int link[MAXM];
int lx[MAXM];
int ly[MAXM];
int slack[MAXM];
bool visx[MAXM];
bool visy[MAXM];
int N;
inline bool find(int cnt)
{
visx[cnt] = true;
for(int i = 0; i < N; ++i)
if(!visy[i])
{
int tmp = lx[cnt]+ly[i]-g[cnt][i];
if(!tmp)
{
visy[i] = true;
if(link[i] == -1 || find(link[i]))
{
link[i] = cnt;
return true;
}
}
else slack[i] = MIN(slack[i], tmp);
}
return false;
}
inline void work()
{
N = MAX(n-1, m);
memset(link, -1, N*sizeof(int));
for(int i = 0; i < N; ++i)
{
lx[i] = -INF;
for(int j = 0; j < N; ++j)
lx[i] = MAX(lx[i], g[i][j]);
}
for(int i = 0; i < N; ++i)
{
memset(slack, INF, N*sizeof(int));
while(1)
{
memset(visx, false, N*sizeof(bool));
memset(visy, false, N*sizeof(bool));
if(find(i)) break;
int d = INF;
for(int j = 0; j < N; ++j)
if(!visy[j])
d = MIN(d, slack[j]);
for(int j = 0; j < N; ++j)
if(visx[j]) lx[j] -= d;
for(int j = 0; j < N; ++j)
if(visy[j]) ly[j] += d;
else slack[j] -= d;
}
}
}
inline void print()
{
for(int i = 0; i < n-1; ++i) printf("%d\n", tree_w[i]-lx[i]);
for(int i = 0; i < m; ++i) printf("%d\n", else_w[i]+ly[i]);
}
int main()
{
init();
work();
print();
return 0;
}