zoukankan      html  css  js  c++  java
  • [SCOI2012]滑雪与时间胶囊

    题目:BZOJ2753、洛谷P2573、codevs2399。

    题目大意:给你一张带权有向图(由于存在高度限制,所以边是有向的),问你从1开始最多能深度优先遍历多少个点(使用时间胶囊即为回溯),在遍历最多点的情况下,使得所有经过的边的权值和最小(由于深度优先遍历,所以就是求“有向图的最小生成树”)。

    解题思路:第一问很容易,深搜遍历即可。

    在遍历的时候把有用的边记录下来。

    第二问其实就是求最小生成树,但边是有向的,怎么办?

    这里仍然可以使用Kruskal解决。

    我们可以在对边排序的时候,以终点的高度为第一关键字,从大到小排,以边权为第二关键字,从小到大排。

    要保证有向图的“最小生成树”正确,我们必须从高到低按次序遍历下来。

    而以终点的高度从大到小排,就能保证所遍历的点一定是从大到小的,也就保证了答案的正确性。

    然后Kruskal跑即可。

    时间复杂度$O(mlog_2 m)$,时间限制5s,强的数据能在1s左右运行完。

    注意答案会超出$2^{32}$,要用64位整数。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,m,h[100002],cnt,head[100002],fa[100002],cnt2,mxJD,head2[100002];
    long long mxDS;
    bool vis[100002];
    int dad(int x){return fa[x]==x?x:fa[x]=dad(fa[x]);}
    struct edge{
    	int from,to,dis,nxt;
    	bool operator<(const edge& rhs)const{
    		if(h[to]!=h[rhs.to])return h[to]>h[rhs.to];
    		return dis<rhs.dis;
    	}
    }e[1000005<<1],e2[1000005<<1];
    inline int readint(){
    	char c=getchar();
    	for(;!isdigit(c);c=getchar());
    	int d=0;
    	for(;isdigit(c);c=getchar())
    	d=(d<<3)+(d<<1)+(c^'0');
    	return d;
    }
    void dfs(int now){
    	vis[now]=true;
    	++mxJD;
    	for(int i=head[now];i;i=e[i].nxt){
    		e2[++cnt2]=(edge){e[i].from,e[i].to,e[i].dis,head2[e[i].from]};
    		head2[e[i].from]=cnt2;
    		if(!vis[e[i].to])dfs(e[i].to);
    	}
    }
    int main(){
    	memset(head,0,sizeof head);
    	cnt=cnt2=mxJD=mxDS=0;
    	n=readint(),m=readint();
    	for(int i=1;i<=n;++i)h[i]=readint(),fa[i]=i;
    	while(m--){
    		int u=readint(),v=readint(),t=readint();
    		if(h[u]>=h[v]){
    			e[++cnt]=(edge){u,v,t,head[u]};
    			head[u]=cnt;
    		}//NOT else
    		if(h[u]<=h[v]){
    			e[++cnt]=(edge){v,u,t,head[v]};
    			head[v]=cnt;
    		}
    	}
    	memset(head2,0,sizeof head2);
    	memset(vis,0,sizeof vis);
    	dfs(1);
    	printf("%d ",mxJD);
    	sort(e2+1,e2+cnt2+1);
    	for(int i=1;i<=cnt2;++i){
    		int a=dad(e2[i].from),b=dad(e2[i].to);
    		if(a!=b){
    			mxDS+=e2[i].dis;
    			fa[b]=a;
    			if(--mxJD<2)break;
    		}
    	}
    	printf("%lld
    ",mxDS);
    	return 0;
    }
    
  • 相关阅读:
    iOS 7用户界面过渡指南
    断言
    UIView的任意圆角
    ios与js交互获取webview元素和赋值
    JSONModel解析Dictionary To Model /JSON To Model
    Mac测试模拟慢网速
    MySQL批量调整数据表里的日期
    博客园查询自己网站二级目录被百度收录的情况
    windows文件夹里批量更新文件后缀
    git 学习
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7761522.html
Copyright © 2011-2022 走看看