• 【AT2434】JOI 公園 (JOI Park) 最短路+贪心


    题解

    我的歪解

    我首先想的是分治,我想二分肯定不行,因为它是没有单调性的。

    我想了一下感觉它的大部分数据应该是有凸性的(例如(y=x^2)的函数图像),所以可以三分。

    下面是我的三分代码(骗了不少分)

    三分模板没过的我居然瞎歪歪了一个三分

    歪解code:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<queue>
    #define ll long long
    #define R register
    #define N 400005
    #define INF 0x7fffffffffffLL
    using namespace std;
    template<typename T>inline void read(T &a){
        char c=getchar();T x=0,f=1;
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        a=f*x;
    }
    ll n,m,c,tot,h[N],vis[N],pd[N];
    ll dist[N],sum,now_ans,now;
    struct bian{
    	int u,v;
    	ll w;
    }b[N];
    struct node{
    	int nex,to;
    	ll dis;
    }edge[N<<1];
    inline void add(R int u,R int v,R ll w){
    	edge[++tot].nex=h[u];
    	edge[tot].to=v;
    	edge[tot].dis=w;
    	h[u]=tot;
    }
    inline void spfa(R int s){
    	for(R int i=1;i<=n;i++)dist[i]=INF;
    	queue<int> q;q.push(s);dist[s]=0;vis[s]=1;
    	while(!q.empty()){
    		R int x=q.front();q.pop();vis[x]=0;
    		for(R int i=h[x];i;i=edge[i].nex){
    			R int xx=edge[i].to;
    			if(dist[xx]>dist[x]+edge[i].dis){
    				dist[xx]=dist[x]+edge[i].dis;
    				if(!vis[xx]){
    					vis[xx]=1;
    					q.push(xx);
    				}
    			}
    		}	
    	}
    }
    inline ll check(R ll mid){
    	ll tot=0;
    	for(R int i=1;i<=n;i++)pd[i]=0;
    	for(R int i=1;i<=n;i++)
    		if(dist[i]<=mid)pd[i]=1;
    	for(R int i=1;i<=m;i++)
    		if(pd[b[i].u]&&pd[b[i].v])
    			tot+=b[i].w;
    	return tot-mid*c;//这是你能节省的
    }
    int main(){ 
    	read(n);read(m);read(c);
    	for(R int i=1;i<=m;i++){
    		read(b[i].u);read(b[i].v);read(b[i].w);
    		add(b[i].u,b[i].v,b[i].w);add(b[i].v,b[i].u,b[i].w);sum+=b[i].w;
    	}
    	spfa(1);
    	R ll l=0,r=sum;
    	while(l<=r){
    		R ll tmp=(r-l)/3;
    		R ll mid1=l+tmp;
    		R ll mid2=r-tmp;
    		if(check(mid1)>check(mid2)) r=mid2-1;
    		else l=mid1+1;
    	}
    	ll tmp=check(l),temp=check(r);
    	if(tmp>temp)now=l,now_ans=tmp;
    	else now=r,now_ans=temp;
    	printf("%lld
    ",sum-now_ans);
        return 0;
    }
    

    当然了,三分本来就是一个非常好的骗分算法(也会是正解),有些题在加一些暴力,一定会有神奇的效果;

    讲课老师说加上暴力这道题应该可以(A)掉,但懒惰的我并没有去实践,有兴趣的可以试一试;

    正解

    这其实是一道经典的最短路的一种题型。

    先跑一遍(SPFA),处理出(dist)数组;

    然后再利用(dist)数组处理出每一条边的(maxdis);

    (maxdis)数组从小到大排序(结构体排序);

    img

    看完图应该都懂了吧。

    code:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<queue>
    #define ll long long
    #define R register
    #define N 800005
    #define int long long
    #define INF 9999999999999999LL
    using namespace std;
    template<typename T>inline void read(T &a){
        char c=getchar();T x=0,f=1;
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        a=f*x;
    }
    ll n,m,c,tot,h[N],vis[N],pd[N],maxdis[N];
    ll dist[N],sum,ans,maxsum;
    struct bian{
    	int u,v,w; 
    }b[N];
    struct node{
    	int nex,to,dis;
    }edge[N<<1];
    struct MAX{
    	int maxdis,id;
    	friend bool operator < (const MAX &a,const MAX &b){
    		return a.maxdis<b.maxdis;
    	}
    }md[N];
    inline void add(R int u,R int v,R int w){
    	edge[++tot].nex=h[u];
    	edge[tot].to=v;
    	edge[tot].dis=w;
    	h[u]=tot;
    }
    inline void spfa(R int s){
    	for(R int i=1;i<=n;i++)dist[i]=INF;
    	queue<int> q;q.push(s);dist[s]=0;vis[s]=1;
    	while(!q.empty()){
    		R int x=q.front();q.pop();vis[x]=0;
    		for(R int i=h[x];i;i=edge[i].nex){
    			R int xx=edge[i].to;
    			if(dist[xx]>dist[x]+edge[i].dis){
    				dist[xx]=dist[x]+edge[i].dis;
    				if(!vis[xx]){
    					vis[xx]=1;
    					q.push(xx);
    				}
    			}
    		}	
    	}
    }
    signed main(){ 
    	read(n);read(m);read(c);
    	for(R int i=1;i<=m;i++){
    		read(b[i].u);read(b[i].v);read(b[i].w);
    		add(b[i].u,b[i].v,b[i].w);add(b[i].v,b[i].u,b[i].w);sum+=b[i].w;
    	}
    	spfa(1);
    	for(R int i=1;i<=m;i++)
    		md[i].maxdis=max(dist[b[i].u],dist[b[i].v]),md[i].id=i;
    	sort(md+1,md+1+m);
    	ans=sum;
    	for(R int i=1;i<=m;i++){
    		sum-=b[md[i].id].w;
    		ans=min(ans,1LL*md[i].maxdis*c+sum);
    	}
    	printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    链表10-开发可用链表(使用链表)
    LRU简单实现
    图片服务器搭建过程
    scp
    dubbo-admin无法访问
    linux tomcat启动后无法访问
    linux进程端口防火墙
    centos7 jdk
    com.alibaba.dubbo.rpc.RpcException: Fail to start server(url: dubbo://192.16。。
    linux与Unix切换到root用户
  • 原文地址:https://www.cnblogs.com/ZAGER/p/9817918.html
Copyright © 2020-2023  润新知