bzoj3118 Orz the MST

  这个题有原型,上海2004那个mst,加边减边的代价都是1,做法一样,但是那个题单纯形被卡空间了......囧。

  分析一下:对于每条非指定在mst里的边(以下称非树边),它一定存在且仅存在一个出它之外全由树边组成的环里,那么这条非树边一定比环里其它边长,那么我们要么增加这条非树边,要么减少其它树边,方能满足条件。于是就可以对于每条非树边,找到那些和它相关的树边,就可以列出线性规划式了。利用对偶转化成松弛形式,就可以单纯形了。这里额外提一下,对于这种约束的系数为0,1,-1,所求值为整数的线性规划,可以用简化版单纯形法,详见代码:

  

orz the mst
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #define maxn 500
  7 #define maxm 5000
  8 #define inf 2147483647
  9 using namespace std;
 10 struct et
 11 {
 12     int s,t,next,sign;
 13 }e[maxm];
 14 int mat[1200][30000];
 15 int fir[maxn],val[maxm],q[maxm],pre[maxn],next[maxm],up[maxm],down[maxm];
 16 bool v[maxm],vis[maxn];
 17 int n,m,tot,cnt,num;
 18 
 19 void find(int st,int ed,int p)
 20 {
 21     memset(vis,0,sizeof(vis));
 22     int head=0,tail=1;
 23     q[1]=st;pre[st]=0;vis[st]=1;
 24     while (head<tail)
 25     {
 26         int now=q[++head];
 27         for (int j=fir[now];j;j=e[j].next)
 28         {
 29             int k=e[j].t;
 30             if (v[e[j].sign]&&!vis[k]) 
 31             {
 32                 pre[k]=j,q[++tail]=k,vis[k]=1;
 33                 if (k==ed) break;
 34             }
 35         }
 36     }
 37     for (int j=pre[ed];j;j=pre[e[j].s]) 
 38     {
 39         int k=e[j].sign;
 40         ++cnt;
 41         mat[k][cnt]=mat[p][cnt]=1;
 42         mat[0][cnt]=val[k]-val[p];
 43     }
 44 }
 45 
 46 void change(int x,int e)
 47 {
 48     int last=-1;
 49     for (int i=0;i<=cnt;i++)
 50         if (mat[x][i])
 51         {
 52             next[i]=last;
 53             last=i;
 54         }
 55     for (int i=0;i<=num;i++)
 56     {
 57         if (i==x||mat[i][e]==0) continue;
 58         for (int j=last;j!=-1;j=next[j])
 59         {
 60             if (j==e) continue;
 61             mat[i][j]-=mat[i][e]*mat[x][j];
 62         }
 63         mat[i][e]=-mat[i][e];
 64     }
 65 }
 66     
 67 int simplex()
 68 {
 69     while (1)
 70     {
 71         int now=0;
 72         for (int i=1;i<=cnt;i++)
 73             if (mat[0][i]>0) { now=i; break; }
 74         if (now==0) return -mat[0][0];
 75         int tmp,mi=inf;
 76         for (int i=1;i<=num;i++)
 77             if (mat[i][now]>0&&mat[i][0]<mi)
 78                 mi=mat[i][0],tmp=i;
 79         change(tmp,now);
 80     }
 81 }
 82 
 83 void add(int x,int y)
 84 {
 85     e[++tot].s=x; e[tot].t=y; e[tot].next=fir[x]; fir[x]=tot;
 86 }
 87 
 88 int main()
 89 {
 90     //freopen("mst.in","r",stdin);
 91     scanf("%d%d",&n,&m);
 92     int x,y,z;
 93     for (int i=1;i<=m;i++)
 94     {
 95         scanf("%d%d%d%d%d%d",&x,&y,&z,&v[i],&up[i],&down[i]);
 96         add(x,y);
 97         e[tot].sign=i;
 98         add(y,x);
 99         e[tot].sign=i;
100         val[i]=z;
101     }
102     for (int i=1;i<=m;i++)
103         if (!v[i]) 
104             find(e[i*2].s,e[i*2].t,i);
105     num=m;
106     for (int i=1;i<=num;i++) mat[i][0]=v[i]?down[i]:up[i];
107     //cout<<num<<' '<<cnt<<endl;
108     //for (int i=0;i<=num;i++)
109     //{
110     //    for (int j=0;j<=cnt;j++)
111     //        cout<<mat[i][j]<<' ';
112     //    cout<<endl;
113     //}
114     int ans=simplex();
115     printf("%d\n",ans);
116     return 0;
117 }

 

单纯形是在太快了......就是空间大了点

转载于:https://www.cnblogs.com/zig-zag/archive/2013/04/20/3032858.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值