一开始以为是最小割,可是树边与非树边可以同时改变,令人很不爽。
结果发现是htx的noip模拟题,是用km算法解决的。。。
于是又碰到了一个km算法非最优匹配应用。
设w[i]为树边,w[j]为非树边,我们只会减树边、加非树边,所以可以写出不等式(w[i]-l[i])<=(w[j]+r[j]),移项得w[i]-w[j]<=l[i]+r[j],这就很像km算法中的顶标不等式,而km算法正好能使l[i]+r[j]最小,那么问题解决。
这类问题的重要特点便是w[i]-w[j]<=l[i]+r[j],并且最小化右式,一开始我想直接用边权做顶标,套用不等式,可是没办法解决最小化问题,所以还是要抓住问题关键。
#include <cstdio> #include <cstdlib> #include <cstring> int tail[50000],tail2[50000],next[50000],cc[50000],next2[50000],cost2[50000],pow[50000],sora[50000],sora2[50000],p[50000],q[50000],st[50000],lx[50000],ly[50000],vx[50000],vy[50000],d[50000],b[50000],slack[50000]; int ss,ss2,n,m; const int oo=1073741819; void origin(){for (int i=1;i<=n+m-1;i++) tail[i]=i,tail2[i]=i;ss=n+m-1,ss2=n+m-1;} void link(int x,int y,int i){ss++,next[tail[x]]=ss,tail[x]=ss,sora[ss]=y,pow[ss]=i;} void link2(int x,int y,int z){ss2++,next2[tail2[x]]=ss2,tail2[x]=ss2,sora2[ss2]=y,cost2[ss2]=z;if (z>lx[x]) lx[x]=z;} int min(int x,int y) {return (x<y) ? x : y;} void bfs(int x,int y,int k) { int h,r,i,ne,na; memset(d,127,sizeof(d)); h=0,st[r=1]=x,d[x]=0,p[x]=0; for (;h<r;) { ne=st[++h]; for (i=ne;next[i]!=0;) { i=next[i],na=sora[i]; if (d[ne]+1<d[na]) d[na]=d[ne]+1,p[na]=ne,q[na]=pow[i],st[++r]=na; } } for (i=y;p[i];i=p[i]) link2(q[i],k,cc[q[i]]-cc[k]); } int find(int x) { if (vx[x]) return 0; vx[x]=1; for (int i=x,tmp,ne;next2[i]!=0;) { i=next2[i],ne=sora2[i]; tmp=lx[x]+ly[ne]-cost2[i]; if ((!vy[ne])&&(0==tmp)) { vy[ne]=1; if ((0==b[ne])||(find(b[ne]))) { b[ne]=x;return 1; } } else if (tmp<slack[ne]) slack[ne]=tmp; } return 0; } void km() { memset(b,0,sizeof(b)); for (int i=1,j,d;i<=n-1;i++) { memset(vx,0,sizeof(vx)),memset(vy,0,sizeof(vy)),memset(slack,127,sizeof(slack)); if (35==i) d--; for (;!find(i);) { d=oo; for (j=n;j<=m;j++) if (!vy[j]) d=min(d,slack[j]); for (j=n;j<=m;j++) if (vy[j]) ly[j]+=d;else slack[j]-=d; for (j=1;j<=n-1;j++) if (vx[j]) lx[j]-=d; memset(vx,0,sizeof(vx)),memset(vy,0,sizeof(vy)); } } } void init() { int i,x,y,z; scanf("%d%d\n",&n,&m); origin(); for (i=1;i<=m;i++) { scanf("%d%d%d\n",&x,&y,&z);cc[i]=z; if (i<=n-1) link(x,y,i),link(y,x,i);else bfs(x,y,i),ly[i]=0; } for (i=m+1;i<=m+n-1;i++) for (int j=1;j<=n-1;j++) link2(j,i,0); m=m+n-1; km(); for (i=1;i<=n-1;i++) printf("%d\n",cc[i]-lx[i]); for (i=n;i<=m-n+1;i++) printf("%d\n",cc[i]+ly[i]); } int main() { freopen("ti.in","r",stdin); freopen("ti.out","w",stdout); init(); return 0; }