zoukankan      html  css  js  c++  java
  • codeforces1253F(图转换为树减少复杂度)

    题意:

    给定一个无向图,其中1-k为充电桩,然后给定q个询问(u_i, v_i)(都是充电桩),然后问从其中一个充电桩到达另外一个充电桩需要最小的电池的容量。
    每经过一条边都需要消耗一定的能量,到达另外一个充电桩会自动的把电充好。

    题解

    首先计算每个非充电桩的点到充电桩的最短距离
    然后对于每一条边u-v,我们计算他们到各自的充电桩的最短距离+边权重,然后把u'-v',dis_u+dis_v+w加到新的图中
    然后就是并查集,注意合并是有序的

    最后查询利不断的向上就能进行查询了。

    代码

    #include<bits/stdc++.h>
    #define mp std::make_pair
    using namespace std;
    
    typedef long long LL;
    typedef std::pair<int,int> pi;
    
    const int N=100005;
    const LL inf=(LL)1e15;
    
    int n,m,k,q,cnt,last[N],fro[N],f[N],sz[N];
    LL dis[N],val[N];
    struct edge{int to,next;LL w;}e[N*6];
    struct data{int x,y;LL w;}a[N*3];
    std::priority_queue<std::pair<LL,int> > que;
    bool vis[N];
    
    void addedge(int u,int v,LL w)
    {
    	e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
    	e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
    }
    
    void dij()
    {
    	for (int i=1;i<=k;i++) dis[i]=0,fro[i]=i,que.push(mp(0,i));
    	for (int i=k+1;i<=n;i++) dis[i]=inf;
    	while (!que.empty())
    	{
    		int u=que.top().second;que.pop();
    		if (vis[u]) continue;
    		vis[u]=1;
    		for (int i=last[u];i;i=e[i].next)
    			if (dis[u]+e[i].w<dis[e[i].to])
    			{
    				dis[e[i].to]=dis[u]+e[i].w;
    				fro[e[i].to]=fro[u];
    				que.push(mp(-dis[e[i].to],e[i].to));
    			}
    	}
    }
    
    bool cmp(data a,data b)
    {
    	return a.w<b.w;
    }
    //没有进行路径的压缩
    int find(int x)
    {
    	return f[x]==x?x:find(f[x]);
    }
    
    LL query(int x,int y)
    {
    	LL ans=0;
    	while (x!=y)
    	{
    		if (sz[x]>sz[y]) std::swap(x,y);
    		ans=std::max(ans,val[x]);x=f[x];
    	}
    	return ans;
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&k,&q);
    	for (int i=1;i<=m;i++)
    	{
    		int x,y;LL w;scanf("%d%d%lld",&x,&y,&w);
    		addedge(x,y,w);
    	}
    	dij();
    	for (int i=1;i<=cnt;i+=2)
    	{
    		int x=e[i].to,y=e[i+1].to;LL w=dis[x]+dis[y]+e[i].w;
    		//fro[i] i最短路要经过哪个电桩
    		a[i/2+1]=(data){fro[x],fro[y],w};
    	}
    	std::sort(a+1,a+m+1,cmp);
    
    	for (int i=1;i<=k;i++) f[i]=i,sz[i]=1;
    	//有点最小生成树的感觉。
    	for (int i=1;i<=m;i++)
    	{
    	    cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].w<<endl;
    		int x=find(a[i].x),y=find(a[i].y);
    		if (x==y) continue;
    		cout<<"test "<<x<<" "<<y<<endl;
    		if (sz[x]>sz[y]) std::swap(x,y);
    		f[x]=y;sz[y]+=sz[x];val[x]=a[i].w;
    	}
    	while (q--)
    	{
    		int x,y;scanf("%d%d",&x,&y);
    		printf("%lld
    ",query(x,y));
    	}
    	return 0;
    }
    /*
    9 11 3 2
    1 3 99
    1 4 5
    4 5 3
    5 6 3
    6 4 11
    6 7 21
    7 2 6
    7 8 4
    8 9 3
    9 2 57
    9 3 2
    3 1
    2 3
    */
    
    
  • 相关阅读:
    2020Java面试题整理
    Oracle中使用Merge Into去除数据库重复记录
    Oracle修改sort_area_size,workarea_size_policy
    免费接口
    Java 将日期或秒数转换为日时分秒,如:2天3小时23分32秒
    linux环境下Mysql不区分大小写配置
    Oracle分区测试
    JS倒计时刷新页面
    JS获取table列数据
    Sql Server 2008日志清理
  • 原文地址:https://www.cnblogs.com/babydragon/p/11876723.html
Copyright © 2011-2022 走看看