BZOJ 3118 Orz the MST 线性规划

来源:互联网 发布:华为网络认证多少钱 编辑:程序博客网 时间:2024/06/13 17:06

题意:链接

方法:线性规划

解析:

这道题我也是orz了。

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

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

这个图也是建了一阵子。

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

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

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

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

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

结合之前的结论

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

则有如下限制

Xj+Wj>=WiXi

Xj+Wj>=WkXk

Xi+Xj>=WiWj

Xk+Xj>=WkWj

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

我们的目标函数是什么?

最小化mi=1XiCi

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

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


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

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

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 310#define M 1010#define INF 0x7f7f7f7fusing 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]);}
0 0