[BZOJ3118]Orz the MST(单纯形)

题目描述

传送门

题解

这题我的方法好蠢啊
xi 表示第i条边增加了几次, yi 表示第i条边减少了几次,那么目标函数就是最小化 Aixi+Biyi
然后对于每一条非树边,它的两个端点对应的树链上的每一条边都应该小于这条非树边,也就是说, xiyi+wixjyj+wj ,因为 wi wj 的大小不定,但是 Ai Bi 一定是正数,所以要将矩阵对偶来满足初始可行解。也就是化成 xjxiyj+yiwiwj 的形式
然后用单纯形解就行了
但是实际上非树边只会增大,树边只会减小,所以一条边设一个未知量就行了,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);
}

你可能感兴趣的:(题解,线性规划)