2018.12.08【NOIP提高組】模擬B組100042. 保留道路
阿新 • • 發佈:2018-12-31
原來的思路是排序g,列舉最大的g,接著將g邊權小於這個g的邊排序做mst。
O(m^2)
我們發現,後面的步驟可以簡化,排完g後,將邊逐條加入一個邊集b中。
i :1-> m 列舉最大的g,(同上)(這條一定要選)mst的答案。
現在我們有n條邊,其中n-1條是我們之前mst篩下的,還有一條(i)是新加的
假設邊集b的s本來是有序的,我們只需將i找一個位置插入(比較s值)即可
再用這n條邊mst
證明:
假如現在固定了g值最大值,設為G,一共有l條邊(邊權都<=G),現在按s屬性做mst,保留了n-1條邊,顯然剩下的l-(n-1)條邊就沒用了,因為剩下的邊不會對後面的答案有影響(對於s這個屬性,它們沒有那n-1條邊優,就算看g,i不斷往後,後面的邊g邊權不斷增大,與它們的取值無關)
#include<bits/stdc++.h> #define ll long long #define N 410 #define M 50010 #define inf (1ll<<60) #define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout); using namespace std; struct edge { ll u,v,g,s; }e[M]; ll n,m,i,j,t,Wg,Ws,tot,cur,ans=inf,father[N],b[M]; bool cmpg(edge x,edge y) {return x.g<y.g;} ll getfather(ll x) {return father[x]==x?x:father[x]=getfather(father[x]);} int main() { //open("road"); scanf("%lld%lld%lld%lld",&n,&m,&Wg,&Ws); for(i=1;i<=m;i++) scanf("%lld%lld%lld%lld",&e[i].u,&e[i].v,&e[i].g,&e[i].s); sort(e+1,e+1+m,cmpg); for(i=1;i<=m;i++) { cur=tot+1; for(j=1;j<=tot;j++) if(e[b[j]].s > e[i].s ) {cur=j;break;} ++tot; if(cur==tot) b[cur]=i; else { for(j=tot;j>cur;j--)b[j]=b[j-1]; b[cur]=i; } ll cnt=0,flag=0; for(j=1;j<=n;j++)father[j]=j; for(j=1;j<=tot;j++) { ll fx=getfather(e[b[j]].u),fy=getfather(e[b[j]].v); if(fx!=fy) { father[fx]=fy; b[++cnt]=b[j]; if(b[j]==i)flag=1; } } if(flag && cnt== n-1)ans=min(ans,Wg*e[i].g+Ws*e[b[cnt]].s); tot=cnt; } printf("%lld",ans==inf?-1:ans); return 0; }