20260526模拟赛
20260526模拟赛
通信网络
题面:
给定一张简单联通无向图和一个整数 \(K\),每条边有非负整数属性 \(c_i,d_i\),你需要为每条边选择一个非负整数 \(x_i\),设其边权为 \(c_i+x_i\) 的图上最小生成树边权和为 \(MST\),最大化 \(K\times MST-\sum d_ix_i\),或报告正无穷。\(n\leq 50,m\leq 200\)。
题解:
设 \(T\) 为所有生成树的集合。对每棵生成树 \(t \in T\),记 \(f_{t,e} = [e\in t]\),令 \(v\) 表示最小生成树的权值,限制是 \(\forall t \in T, v \leq \sum_e (c_e + x_e) f_{t,e}\)。
原问题写成线性规划形式是 \(\max kv - \sum d_e w_e\) 要求 \(\forall t \in T,v - \sum_e x_e f_{t,e} \leq \sum_e c_e f_{t,e}\) 变量 $ x_e \geq 0$。
对这个问题对偶之后变成:设每棵生成树变量是 \(y_t \geq 0\),\(\min\sum_t \left(\sum_e c_e f_{t,e}\right) y_t\) 限制 \(\sum_t y_t \geq k;\forall e \sum_t f_{t,e} y_t \leq d_e\)。
令 \(w_e = \sum_t f_{t,e} y_t\),若 \(\sum_t y_t > k\),则一定存在方案 \(\sum_t y'_t=k,y'_t\leq y_t\),答案不会变劣。所以不妨令 \(\sum_t y_t = k\)。问题变为 \(\sum_e w_e = k(n-1), 0 \leq w_e \leq d_e\),存在 \(k\) 棵生成树对于每条边的累计覆盖次数是 \(w_e\),最小化 \(\sum_e c_e w_e\)。
生成树覆盖这个略显抽象的条件有经典结论是它等价于 \(\sum_{e \in E(S)} w_e \leq k(|S| - 1) \quad (\forall \emptyset \neq S \subseteq V)\),其中 \(E(S)\) 表示点集 \(S\) 的导出子图中的边集。
将所有边按 \(c_e\) 从小到大排序。依次考虑每条边 \(i\),尽可能让它的 \(w_i\) 取到最大。设当前边 \(i\) 的两个端点为 \(u,v\),前面已经确定的边权记为 \(g_e\),后面的边暂时视作 \(0\)。那么 \(w_i\) 的最大可取值为:\(w_i = \min\left(d_i,\ \min_{u,v \in S} \left(k(|S| - 1) - \sum_{e \in E(S), e \neq i} g_e\right)\right)\)。
设当前为 \((u,v)\),要求出 \(\min_{u,v \in S} \left(k(|S| - 1) - \sum_{e \in E(S), e \neq i} g_e\right)\),这可以最小割解决:
对于每条已确定的边 \(e=(a,b)\),加入边 \((S,a,g_e),(a,b,g_e)\)。对于每个顶点 \(x \neq u,v\),加入边 \((x,T,k)\)。
最小割值为 \(\text{cut}=\sum g_e-\sum_{e\in E(S),e\not =i}g_e+k(|S|-2)\)。其中一个点被割到了源点集合中表示其在 \(S\) 中,我们连边时钦定 \(u,v\) 已经在 \(S\) 中。
最后若 \(\sum g_e=k(n-1)\) 不成立则答案为正无穷。
代码
#include<bits/stdc++.h>
#define ll long long
#define fir first
#define sec second
using namespace std;
inline int read(){
int s=0,k=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') k=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
s=(s<<3)+(s<<1)+(c^48);
c=getchar();
}
return s*k;
}
const int N=55,M=205;
const ll inf=1e18+7;
int n,m;ll K,w[M];
struct edge{
int u,v;ll c,d;
}e[M];
namespace flow{
int head[N],E[N],dep[N],cnt,S,T;
struct edge{
int v,nxt;ll w;
}e[M*2+N<<1];
void init(int n){
S=0;T=n+1;cnt=1;
for(int i=S;i<=T;i++) head[i]=0;
}
void add(int u,int v,ll w){
e[++cnt]={v,head[u],w};
head[u]=cnt;
e[++cnt]={u,head[v],0};
head[v]=cnt;
}
bool bfs(){
for(int i=S;i<=T;i++) dep[i]=0,E[i]=head[i];
queue<int>q; q.push(S);dep[S]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x],v;i;i=e[i].nxt){
v=e[i].v;
if(e[i].w&&!dep[v]){
dep[v]=dep[x]+1;
q.push(v);
}
}
}
return dep[T]!=0;
}
ll dfs(int x,ll W){
if(x==T) return W;
ll now=0;
for(int i=E[x],v;i;i=e[i].nxt){
E[x]=i;v=e[i].v;
if(e[i].w&&dep[v]==dep[x]+1){
ll tmp=dfs(v,min(e[i].w,W-now));
if(!tmp) dep[v]=-1;
else{
now+=tmp;
e[i].w-=tmp;
e[i^1].w+=tmp;
if(now==W) return now;
}
}
}
return now;
}
ll dinic(){
ll ans=0,x=0;
while(bfs()) while(x=dfs(S,inf)) ans+=x;
return ans;
}
}
int main(){
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
n=read();m=read();K=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),c=read(),d=read();
e[i]={u,v,c,d};
}
sort(e+1,e+1+m,[&](edge x,edge y){
return x.c<y.c;
});
ll sum=0;
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
flow::init(n);
for(int j=1;j<=m;j++){
if(w[j]==0) continue;
flow::add(0,e[j].u,w[j]);
flow::add(e[j].u,e[j].v,w[j]);
}
for(int i=1;i<=n;i++)
if(i!=u&&i!=v) flow::add(i,n+1,K);
ll ans=flow::dinic();
w[i]=min(e[i].d,ans+K-sum);
sum+=w[i];
}
if(sum!=K*(n-1)){
puts("-1");
return 0;
}
ll ans=0;
for(int i=1;i<=m;i++) ans+=e[i].c*w[i];
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号