给定 N 个点以及 M 条边,每条边可以花费一定的代价修改权值,求需要花费的最小代价使得规定的 N−1 条边为这张图的最小生成树。
把规定的 N−1 条边构成一棵树,那么其他的边如果加入这张图中,必定会构成一个环。
令 Xi 为第 i 条边修改的权值量, Wi 为第 i 条边原始权值。
对于不需要的边 i ,dfs出它加入图后构成的环,环中除了这条边以外的边 j 必须满足
Wj−Xj≤Wi+Xj
那么就可以线性规划来做这道题。
#include
#include
#include
#include
#define N 310
#define M 1010
#define inf (1<<30)
#define eps 1e-7
using namespace std;
int n,m,x,y,w,f,a,b,tt,tt0,G[N],tail,cnt;
double A[M][M<<2],B[M],C[M<<2],v;
struct edge{
int nx,t,w,x,g;
}E[M<<2],Q[M<<1];
struct nteg{
int l,r,w,x,g;
}ne[M];
inline void reaD(int &x){
char Ch=getchar();x=0;
for(;Ch>'9'||Ch<'0';Ch=getchar());
for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());
}
inline void InserT(int x,int y,int w,int a,int g){
E[++tt0].nx=G[x];E[tt0].t=y;E[tt0].w=w;E[tt0].x=a;E[tt0].g=g;G[x]=tt0;
E[++tt0].nx=G[y];E[tt0].t=x;E[tt0].w=w;E[tt0].x=a;E[tt0].g=g;G[y]=tt0;
}
bool dfs(int x,int y,int l){
if(x==y) return true;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=l){
Q[++tail]=E[i];
if(dfs(E[i].t,y,x))return true;
tail--;
}
return false;
}
void build(nteg x){
tail=0,dfs(x.l,x.r,0);
for(int i=1;i<=tail;i++) A[Q[i].g][++cnt]=1,A[x.g][cnt]=1,C[cnt]=Q[i].w-x.w;
}
inline void pivot(int l,int e){
B[l]/=A[l][e];
for(int i=1;i<=n;i++)if(i!=e)A[l][i]/=A[l][e];
A[l][e]=1/A[l][e];
for(int i=1;i<=m;i++)if(i!=l&&fabs(A[i][e])>eps){
B[i]-=A[i][e]*B[l];
for(int j=1;j<=n;j++)if(j!=e) A[i][j]-=A[i][e]*A[l][j];
A[i][e]*=-A[l][e];
}
v+=B[l]*C[e];
for(int i=1;i<=n;i++)if(i!=e)C[i]-=C[e]*A[l][i];
C[e]*=-A[l][e];
}
inline int Simplex(){
int i,l,e;
while(1){
for(i=1;i<=n;i++)
if(C[i]>eps) break;
if((e=i)>n) return (int)(v+0.5);
double tmp=inf;
for(int i=1;i<=m;i++)
if(A[i][e]>eps&&tmp>B[i]/A[i][e]) tmp=B[i]/A[i][e],l=i;
if(tmp==inf) return inf;
pivot(l,e);
}
}
int main(){
reaD(n);reaD(m);
for(int i=1;i<=m;i++){
reaD(x);reaD(y);reaD(w);reaD(f);reaD(a);reaD(b);
if(f) InserT(x,y,w,b,i),B[i]=b;
else ne[++tt]=(nteg){x,y,w,a,i},B[i]=a;
}
for(int i=1;i<=tt;i++) build(ne[i]);
n=cnt;
return printf("%d\n",Simplex()),0;
}