zoukankan      html  css  js  c++  java
  • IOI2021集训队作业 277BK Journey from Petersburg to Moscow

    题目

    一个无向图,一个路径的代价为经过的边的代价的前(k)大和(不足就全部)。问最短路。

    (n,mle 3000)


    枚举第(k)大的边权(lim),把小于(lim)的边连着的点缩起来,大于(lim)的边连上。然后跑恰好(k)长度的最短路。

    恰好(k)长度的最短路不好做,可以将每个边权(w)变成(w-lim),最后加上(lim*k)

    这样不超过(k)长度的边,不足的部分相当于用(lim)长度来补。

    时间(O(n(n+m)lg m))


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 3010
    #define ll long long
    #define INF 0x7f7f7f7f7f7f7f7f
    int n,m,k;
    struct edge{
    	int u,v,w; 
    } ed[N];
    bool cmped(edge a,edge b){return a.w<b.w;}
    struct EDGE{
    	int to,w;
    	EDGE *las;
    };
    struct Graph{
    	EDGE e[N*2];
    	int ne;
    	EDGE *last[N];
    	void link(int u,int v,int w){
    		e[ne]={v,w,last[u]};
    		last[u]=e+ne++;
    	}
    	void clear(){
    		ne=0;
    		memset(last,0,sizeof(EDGE*)*(n+1));
    	}
    } F;
    int fa[N];
    int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
    ll f[N];
    pair<int,ll> h[N*N];
    int nh;
    bool cmph(pair<int,ll> a,pair<int,ll> b){
    	return a.second>b.second;
    }
    ll S_P(){
    	memset(f,127,sizeof f);
    	int S=getfa(1);
    	f[S]=0;
    	h[0]={S,0};
    	nh=1;
    	while (nh){
    		int x=h[0].first;
    		ll s=h[0].second;
    		pop_heap(h,h+nh--,cmph);
    		if (s>f[x]) continue;
    		for (EDGE *ei=F.last[x];ei;ei=ei->las)
    			if (s+ei->w<f[ei->to]){
    				f[ei->to]=s+ei->w;
    				h[nh]={ei->to,f[ei->to]};
    				push_heap(h,h+nh++,cmph);
    			}
    	}
    	int T=getfa(n);
    	return f[T];
    }
    int main(){
    //	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	scanf("%d%d%d",&n,&m,&k);
    	for (int i=1;i<=m;++i)
    		scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w);
    	sort(ed+1,ed+m+1,cmped);
    	for (int i=1;i<=n;++i)
    		fa[i]=i;
    	for (int i=1;i<=m;++i)
    		F.link(ed[i].u,ed[i].v,ed[i].w),F.link(ed[i].v,ed[i].u,ed[i].w);
    	ll ans=S_P();
    	for (int i=1;i<=m;++i){
    		int x=getfa(ed[i].u),y=getfa(ed[i].v);
    		if (x!=y){
    			fa[x]=y;
    			F.clear();
    			for (int j=i+1;j<=m;++j){
    				x=getfa(ed[j].u),y=getfa(ed[j].v);
    				int w=ed[j].w-ed[i].w;
    				if (x!=y)
    					F.link(x,y,w),F.link(y,x,w);
    			}
    			ans=min(ans,(ll)k*ed[i].w+S_P());
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    nodeJs小练习之爬取北京昌平区房价
    2016,加油,奋斗
    1339 字符串王国的种族
    1333 明信片和照片
    1316 你能知道这是几进制数?
    1309 简化版九宫格
    1295 爱翻译
    1288 幸运转盘(一)
    1287 孙武练兵
    1284 喜羊羊的新年礼物
  • 原文地址:https://www.cnblogs.com/jz-597/p/13823616.html
Copyright © 2011-2022 走看看