传送门
这题我的方法好蠢啊
令 xi 表示第i条边增加了几次, yi 表示第i条边减少了几次,那么目标函数就是最小化 ∑Ai∗xi+Bi∗yi
然后对于每一条非树边,它的两个端点对应的树链上的每一条边都应该小于这条非树边,也就是说, xi−yi+wi≤xj−yj+wj ,因为 wi 和 wj 的大小不定,但是 Ai 和 Bi 一定是正数,所以要将矩阵对偶来满足初始可行解。也就是化成 xj−xi−yj+yi≤wi−wj 的形式
然后用单纯形解就行了
但是实际上非树边只会增大,树边只会减小,所以一条边设一个未知量就行了,gg
感觉最坏情况下是可以卡成 m2 的啊,但是这题没有卡
#include
#include
#include
#include
#include
using namespace std;
const double eps=1e-9;
const double inf=1e18;
int N,M,U[1005],V[1005],W[1005],A[1005],B[1005],FF[1005];
int tot,point[305],nxt[2005],v[2005],num[2005],h[205],father[305],last[305];
int n,m;
double a[4005][4005],b[4005],c[4005],ans;
void add(int x,int y,int id)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; num[tot]=id;
}
void dfs(int x,int fa)
{
h[x]=h[fa]+1;father[x]=fa;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
last[v[i]]=num[i];
dfs(v[i],x);
}
}
void build(int x,int y,int id)
{
int jd;
// xj-xi-yj+yi<=wi-wj
if (h[x]while (h[x]>h[y])
{
jd=last[x];
++n;
a[jd][n]=-1.0;a[id][n]=1.0;a[jd+M][n]=1.0;a[id+M][n]=-1.0;
c[n]=W[jd]-W[id]+0.0;
x=father[x];
}
while (x!=y)
{
jd=last[x];
++n;
a[jd][n]=-1.0;a[id][n]=1.0;a[jd+M][n]=1.0;a[id+M][n]=-1.0;
c[n]=W[jd]-W[id]+0.0;
x=father[x];
jd=last[y];
++n;
a[jd][n]=-1.0;a[id][n]=1.0;a[jd+M][n]=1.0;a[id+M][n]=-1.0;
c[n]=W[jd]-W[id]+0.0;
y=father[y];
}
}
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.0/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[i][e]*a[l][e];
}
ans+=b[l]*c[e];
for (int i=1;i<=n;++i)
if (i!=e)
c[i]-=c[e]*a[l][i];
c[e]=-c[e]*a[l][e];
}
void simplex()
{
while (1)
{
int e;
for (e=1;e<=n;++e)
if (c[e]>eps) break;
if (e==n+1) break;
double Min=inf,t;int l;
for (int i=1;i<=m;++i)
if (a[i][e]>eps&&(t=b[i]/a[i][e])int main()
{
scanf("%d%d",&N,&M);
for (int i=1;i<=M;++i)
{
scanf("%d%d%d%d%d%d",&U[i],&V[i],&W[i],&FF[i],&A[i],&B[i]);
if (FF[i]) add(U[i],V[i],i),add(V[i],U[i],i);
}
dfs(1,0);
m=M*2;
for (int i=1;i<=M;++i)
b[i]=A[i]+0.0,b[i+M]=B[i]+0.0;
for (int i=1;i<=M;++i)
if (!FF[i]) build(U[i],V[i],i);
simplex();
printf("%.0lf\n",ans);
}