BZOJ 3118 Orz the MST 线性规划

题意:链接

方法:线性规划

解析:

这道题我也是orz了。

刚开始脑抽,仅仅是认为所有标号为1的边都比标号为0的边小即可。

后来与140142讨论了下发现我俩都犯好sb的错误=-=

这个图也是建了一阵子。

回忆之前做过的有关一个无向联通图中,一个边在最小生成树上,必要条件是该边构成的环中,这一边一定不是最大值。

这样的话,题中既然给了在树上的边。

并且很显然树上的边只能增加,不在树上的边只能减小。

所以我们不妨设Xi代表第i条边的变化值

那么我们可以重新显然定义代价Ci。

结合之前的结论

编号为j的标号为0的一条边,与树中的i,k边形成环。

则有如下限制

Xj+Wj>=Wi?Xi

Xj+Wj>=Wk?Xk

Xi+Xj>=Wi?Wj

Xk+Xj>=Wk?Wj

我们可以列出所有诸如此类的限制,并且对于本题的数据,该限制不超过4000。

我们的目标函数是什么?

最小化∑mi=1Xi?Ci

这种形式是不是有点眼熟?

是的,直接用对偶原理即可求解。


然而,该题仍有一种较神的写法博主没有写过

就是这种没有基本可行解的线性规划,我们可以设一个辅助变量来求解。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 310
#define M 1010
#define INF 0x7f7f7f7f
using namespace std;
double a[M][M<<2];
int st[N];
struct line
{
    int u,v,w,ff,a,b;
}l[M];
int head[N],cnt,n,m,top,tot;
struct node
{
    int from,to,ff,no,a,b,next;
}edge[M<<1];
void init()
{
    memset(head,-1,sizeof(head));cnt=1;
}
void edgeadd(int from,int to,int ff,int no)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].ff=ff,edge[cnt].no=no;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
void dfs(int now,int fa,int e,int edge0)
{
    if(now==e)
    {
        while(top)
        {
            tot++;
            int no=st[top--];
            a[no][tot]=1;
            a[edge0][tot]=1;
            a[0][tot]=l[no].w-l[edge0].w;
        }
        return;
    }
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==fa)continue;
        st[++top]=edge[i].no;
        dfs(to,now,e,edge0);
        st[top--]=0;
    }
}
int check()
{
    for(int i=1;i<=tot;i++)
        if(a[0][i]>0)return i;
    return 0;
}
void Simplex()
{
    while(int t=check())
    {
        double limit=INF;
        int choseline;
        for(int i=1;i<=m;i++)
        {
            if(a[i][t]<=0)continue;
            else if(a[i][0]/a[i][t]<limit)limit=a[i][0]/a[i][t],choseline=i;
        }
        if(limit==INF){a[0][0]=INF;break;}
        double di=a[choseline][t];
        for(int i=0;i<=tot;i++)
        {
            if(i==t)a[choseline][i]/=di;
            a[choseline][i]/=di;
        }
        for(int i=0;i<=m;i++)
        {
            if(i==choseline||a[i][t]==0)continue;
            if(i==0)a[i][0]+=a[i][t]*a[choseline][0];
            else a[i][0]-=a[i][t]*a[choseline][0];
            double l=a[i][t];
            for(int j=1;j<=tot;j++)
            {
                if(j==t)a[i][j]=-l*a[choseline][j];
                else a[i][j]-=l*a[choseline][j];
            }
        }
    }
}
int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w,ff,A,b,no;
        scanf("%d%d%d%d%d%d",&u,&v,&w,&ff,&A,&b);
        l[i].u=u,l[i].v=v,l[i].w=w,l[i].ff=ff,l[i].a=A,l[i].b=b;
        if(ff)a[i][0]=b;
        else a[i][0]=A;
        if(ff)edgeadd(u,v,ff,i),edgeadd(v,u,ff,i);
    }
    for(int i=1;i<=m;i++)
    {
        if(l[i].ff==0)
        {
            top=0;
            dfs(l[i].u,0,l[i].v,i);
        }
    }
    Simplex();
    printf("%.0lf\n",a[0][0]);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-14 14:43:29

BZOJ 3118 Orz the MST 线性规划的相关文章

3118: Orz the MST(单纯形)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3118 题意:给出一个图以及图中指定的n-1条边组成的生成树.每条边权值加1或者减去1都有相应的代价.求一个最小代价使得给出的边是最小生成树. 思路:对于每条非树边,必与某些树边形成环.设该非树边的权值为w2,某树边的权值为 w1.最后非树边增加x2,树边减少x1,那么w1-x1<=w2+x2.这样我们可以得到一些式子.代价也知道,这样就转化成线性规划问题.题目求的是最小值,我们可

BZOJ 2654 &amp; 玄学二分+MST

题意: 给一张图,边带权且带颜色黑白,求出一棵至少包含k条白边的MST SOL: 正常人都想优先加黑边或者是白边,我也是这么想的...你看先用白边搞一棵k条边的MST...然后维护比较黑边跟白边像堆一样慢慢往里面加...不过讲课的时候跟原题有点出入...这里只有k条边好像比较难维护... 正解也非常巧妙...首先如果有一棵MST,他所含白边数量多于k,那么我们如果可以适当增加白边的边权那么我们就可以减少它的边而且达到最优....想想很有道理你让我证明那有点日了狗了... 然后我们就二分白边的增加

BZOJ 1061 [Noi2008]志愿者招募 线性规划

题意:链接 方法:线性规划 解析: 不妨对样例加以阐释 3 3 2 3 4 1 2 2 2 3 5 3 3 2 不妨设Xi代表第i种志愿者选Xi个人 那么显然,这题的限制为 X1>=2 X1+X2>=3 X2+X3>=4 而我们要做的是使2?X1+5?X2+2?X3最小化 且Xi>=0 但这显然没有基本可行解,那么就不能用单纯形搞了吗? 并不是 有一个强大的东西叫对偶原理 什么是对偶原理呢? 对于本人的代码 设矩阵a[i][j] 其中a[0][i]代表目标函数的系数 a[i][0]

BZOJ 3112 [Zjoi2013]防守战线 线性规划

题意: 简单叙述: 一个长度为n的序列,在每个点建塔的费用为Ci,有m个区间,每个区间内至少有Dj个塔,求最小花费. 方法:线性规划 解析: 与上一题类似,同样使用对偶原理解题,解法不再赘述. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1010 #define M 10010 #define INF 0x7f7f7f7

bzoj-3118 Orz the MST

题意: 给出一个无向连通图,并指定其中一颗生成树: 每条边上有一个权值vali,如果增大这个权值1则花费Ai,减小1花费Bi: 现在要使指定的生成树为一颗最小生成树,求最小花费: n<=300,m<=1000: 题解: 一道线性规划比较神的题目,前面刷的比较偏水就不刷了: 首先有一点极为显然的东西(我居然没看出来),树上的边一定减小权值,非树上的边一定增大权值: 然后考虑对于一颗生成树要为最小要满足的条件,也就是本题的约束条件: 如同Tarjan算法一样,每一条非树边都会在树上生成一个环: 而

BZOJ 2654: tree( 二分 + MST )

我们给白色的边增加权值 , 则选到的白色边就会变多 , 因此可以二分一下. 不过这道题有点小坑... ------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep( i

【BZOJ 2654】 MST

2654: tree Description 给你一个无向带权连通图,每条边是黑色或白色.让你求一棵最小权的恰好有need条白色边的生成树. 题目保证有解. Input 第一行V,E,need分别表示点数,边数和需要的白色边数. 接下来E行,每行s,t,c,col表示这边的端点(点从0开始标号),边权,颜色(0白色1黑色). Output 一行表示所求生成树的边权和. V<=50000,E<=100000,所有数据边权为[1,100]中的正整数. Sample Input 2 2 1 0 1

BZOJ 1937: [Shoi2004]Mst 最小生成树 [二分图最大权匹配]

传送门 题意: 给一张无向图和一棵生成树,改变一些边的权值使生成树为最小生成树,代价为改变权值和的绝对值,求最小代价 线性规划的形式: $Min\quad \sum\limits_{i=1}^{m} \delta_i$ $Sat\quad $非树边边权$\ge$生成树上路径任何一条边的边权 $i$非树边$j$树边 $w_i+\delta_i \ge w_j-\delta_j$ 然后可以转化成二分图最小顶标和来求解 这里需要求二分图最大权非完美匹配,我的做法是遇到$d[t] < 0$就退出,反正这

BZOJ 2429: [HAOI2006]聪明的猴子( MST )

水题, 求MST即可. -------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; #define sqr(x) ((x) * (x)) const int maxn = 1009; struct edge { int u, v; double w; bool operator < (const e