“花费最多的一条公路的花费尽可能的少”一句话是二分的标志。我们二分花费最多的公路的花费x,然后对于每一条路:如果修建一级公路的费用不大于x,那么就连一条权值为1的边;如果修建二级公路的费用不大于x,就连一条权值为0的边;如果都不能修,就不连边。由于题目中要求所有城市连在一起,而且一级公路要尽可能多,所以我们就跑一遍最大生成树。跑完后,如果发现连不起来或者一级公路的条数小于k,就说明不可行;反之说明可行。
下附AC代码:
#include <cstdio> #include <cstring> #define N 12000 #define M 30000 using namespace std; int x[M],y[M],u[M],v[M],u_[M],v_[M],c1[M],c2[M],n,k,m,fa[N]; int getfa(int xx){ if (fa[xx]==xx) return xx; return fa[xx]=getfa(fa[xx]); } int ok(int num){ int sum=0,tot1=0,tot2=0,i; for (i=1; i<m; i++) if (c1[i]<=num){ tot1++; u[tot1]=x[i]; v[tot1]=y[i];} else if (c2[i]<=num){ tot2++; u_[tot2]=x[i]; v_[tot2]=y[i]; } for (i=1; i<=n; i++) fa[i]=i; int p,q; for (i=1; i<=tot1; i++){ p=getfa(u[i]); q=getfa(v[i]); if (p!=q){ sum++; fa[p]=q; } } if (sum<k) return 0; for (i=1; i<=tot2; i++){ p=getfa(u_[i]); q=getfa(v_[i]); if (p!=q) fa[p]=q; } for (i=2; i<=n; i++) if (getfa(fa[i])!=getfa(fa[1])) return 0; return 1; } int main(){ scanf("%d%d%d",&n,&k,&m); int i; for (i=1; i<m; i++) scanf("%d%d%d%d",&x[i],&y[i],&c1[i],&c2[i]); int r,l,mid; r=1; l=30000; while (r+1<l){ mid=(r+l)/2; if (ok(mid)) l=mid; else r=mid+1; } if (ok(r)) printf("%d",r); else printf("%d",l); return 0; }
2015.2.20
by lych