题目链接:[UVA 11865]Stream My Contest[最小树形图][二分答案]
题意分析:
建立一个从服务器(节点0),到所有大学的网络,在可行的网络中,最小带宽最大的网络对应的带宽是多少?
题目中给出了两个限制:
- 大学间原先是没有网络的,所以需要建立网络,要花费一定的费用,最大预算为C元,且边是单向的。
- 大学间的网络都有一个带宽,在生成的网络中,流量不能超过最小带宽,否则无法送达指定用户。
解题思路:
服务器要送达所有的节点,非常符合最小树形图呀= =。不过本题多了个限制条件,于是变成了求所有生成树中,最小边权的最大值是多少?
可以枚举这个最小边权,然后就变成了,大于这个最小边权的最小树形图是否存在,然后不断二分即可。
个人感受:
题目给的第二个限制条件看了半天,英语捉急= =。另外,两个限制条件底下那句话也让我觉得怪怪的,什么分享带宽什么的Orz
具体代码如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int INF = 0x7f7f7f7f;
const int MAXN = 1e4 + 111;
struct Edge{
int u, v, band, cost;
}edge[MAXN * 2];
int n, m, C, pre[100], vis[100], newid[100], in[100];
void add_edge(int cnt, int u, int v, int band, int cost)
{
edge[cnt + m].u = edge[cnt].u = u;
edge[cnt + m].v = edge[cnt].v = v;
edge[cnt + m].band = edge[cnt].band = band;
edge[cnt + m].cost = edge[cnt].cost = cost;
}
bool zhuLiu(int rt, int V, int miband)
{
ll ret = 0;
while (1)
{
for (int i = 0; i < V; ++i) in[i] = INF;
for (int i = 0; i < m; ++i)
{
int u = edge[i].u, v = edge[i].v;
if (u != v && edge[i].band >= miband && in[v] > edge[i].cost)
{
in[v] = edge[i].cost;
pre[v] = u;
}
}
for (int i = 0; i < V; ++i)
{
if (i != rt && in[i] == INF) return 0;
}
int cnt = 0;
memset(newid, -1, sizeof newid);
memset(vis, -1, sizeof vis);
in[rt] = 0;
for (int i = 0; i < V; ++i)
{
ret += in[i];
int v = i;
while (vis[v] != i && newid[v] == -1 && v != rt)
{
vis[v] = i;
v = pre[v];
}
if (v != rt && newid[v] == -1)
{
for (int u = pre[v]; u != v; u = pre[u]) newid[u] = cnt;
newid[v] = cnt++;
}
}
if (cnt == 0) break;
for (int i = 0; i < V; ++i)
if (newid[i] == -1) newid[i] = cnt++;
for (int i = 0; i < m; ++i)
{
int u = edge[i].u, v = edge[i].v;
edge[i].u = newid[u];
edge[i].v = newid[v];
if (newid[u] != newid[v]) edge[i].cost -= in[v];
}
V = cnt;
rt = newid[rt];
}
return (ret <= C);
}
int main()
{
int t, a, b, c, d; scanf("%d", &t);
while (t --)
{
scanf("%d%d%d", &n, &m, &C);
int mi = INF, mx = 0;
for (int i = 0; i < m; ++i)
{
scanf("%d%d%d%d", &a, &b, &c, &d);
add_edge(i, a, b, c, d);
mi = min(mi, c);
mx = max(mx, c);
}
if (!zhuLiu(0, n, mi)) printf("streaming not possible.\n"); // 原图不存在最小树形图
else
{
int l = mi, r = mx;
while (l <= r)
{
int mid = (l + r) >> 1;
for (int i = 0; i < m; ++i) // 还原原图,因为每一次算法都会改变原图
edge[i] = edge[i + m];
if (zhuLiu(0, n, mid)) l = mid + 1;
else r = mid - 1;
}
printf("%d kbps\n", r);
}
}
return 0;
}