【NOIP模擬】距離
阿新 • • 發佈:2018-11-01
題面
對夢想的持續追求讓實力本身很弱的David一天天變強。
他最終考上了自己所喜歡的大學。
北京有啥好大學想必大家都比我清楚吧。
成都到北京之間有 座城市,城市和城市之間由 條雙向通行的道路相連,城市和城市之間兩兩可達。通過第條道路需要交納 的過路費。Acid公司很喜歡有夢想的年輕人,他們決定對前往高校上學的學生的路費予以補助。補助的方式是,在一條路徑
上,你只需要交納路費最貴的前 條道路的費用就可以了。
如果路徑經過了小於 條道路則不補助(這麼近你自己給嘛~)你的任務是求出David到達夢想中的學校所需要的最小路費。
分析
因為昨晚上才做了一個二分的題,因此拿著就開始二分,然後又是染0和1。。好吧掛得只有15分。。。
就像出題人所言,你看這資料範圍如此小,怎麼會是二分呢??二分的題的n怎麼也是跟了4個0的吧??
正確姿勢
列舉答案中最大的不收費邊設其價值為valx,然後把所有的邊的邊權減去valx,不足 valx的設為0,跑最短路,最後把答案加上k*valx ,然後再對所有的情況取min就是最優解
我們設最短路徑中有x條邊大於k
當 x取到k的時候,答案是正確的。剛好k條邊收了費。
而如果最短路徑中有大於k條邊是正數,我們將從大到小的第y條邊的邊權作為新的valx,並令其為valy。
設原先的最短路為 M,以 valy作為答案,求出的答案將會變為 M-(valy-valx)*x+valy*k這個答案是比M+valx
證明很簡單,抓住valy>valx,x>k,即可,不再贅述。
程式碼
#include<bits/stdc++.h> using namespace std; #define N 3030 #define mp make_pair #define ll long long #define INF 0x7fffffff7fffffff typedef pair<ll,ll> pii; ll n,m,k,cnt,ans=INF; ll vis[N],d[N],first[N]; struct email { ll u,v,w,o; ll nxt; }e[N*4]; inline void add(ll u,ll v,ll o) { e[++cnt].nxt=first[u];first[u]=cnt; e[cnt].u=u;e[cnt].v=v;e[cnt].o=o; } priority_queue<pii>q; ll get() { memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); while(!q.empty())q.pop(); d[1]=0; q.push(mp(-d[1],1)); while(!q.empty()) { pii x=q.top();q.pop(); ll u=x.second; if(vis[u])continue;vis[u]=1; for(ll i=first[u];i;i=e[i].nxt) { ll v=e[i].v,w=e[i].w; if(d[v]>d[u]+w&&d[u]+w<ans) d[v]=d[u]+w,q.push(mp(-d[v],v)); } } return d[n]; } int main() { scanf("%lld%lld%lld",&n,&m,&k); for(ll i=1;i<=m;i++) { ll u,v,o; scanf("%lld%lld%lld",&u,&v,&o); add(u,v,o);add(v,u,o); } for(ll i=0;i<=cnt;i++) { ll del=e[i].o; for(ll j=1;j<=cnt;j++)e[j].w=max((ll)0,e[j].o-del); ans=min(ans,get()+k*del); } printf("%lld\n",ans); return 0; }