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 }
单纯形是在太快了......就是空间大了点
AC without art, no better than WA !