• UPC Graph (最小生成树 || 并查集+二分)


    你活得不快乐的原因是:既无法忍受目前的状态,又没能力改变这一切,可以像只猪一样懒,却无法像只猪一样懒得心安理得。

    (为什么我搜到的励志句子这么好笑哈哈哈)

    Graph

    题目描述
    小 Y 又开始了一段旅途。
    这次,他要经过一个图,从1号点到达n号点,每个点设有休息站。
    小 Y 计划用最多k天走完全程,除第k天外,每一天小 Y 都必须在休息站过夜。所以,一段路必须在同一天走完。
    小 Y 的体力有限,他希望走的路程最大的一天中走的路尽可能少,请求出这个最小值。
    输入
    第一行三个整数n、m、k表示图的顶点数、边数、天数。
    从第二行开始,之后的 m 行,每行三个整数 ui、vi、wi表示从 ui和 vi间有一条双向道路,长度为wi。
    输出
    一行一个正整数,如果小 Y 能走完全程,输出走的路程最大的一天中走的路程最小值,否则输出−1。
    样例输入 Copy
    3 2 4
    3 2 4
    1 2 1
    样例输出 Copy
    4
    提示
    对于100%的数据,2≤n≤k≤7500,0≤m≤200000,1≤wi≤109;保证没有重边和自环。
    等我复习完最小生成树就来写
    题意: (好迷啊)
    思路:
    (1)最小生成树+思维:
    我们求一下该图的最小生成树,如果起点和终点联通的话,答案就是最小生成树中的最大边权,否则就输出-1。为什么呢。
    我们可以先这样想,我把最小生成树中的最大边权改为非最小生成树里的任意边权,都比该边权大。对于最小生成树来说,该边权是最大值,对于剩下的边权来说,该边权是最小值。这不就是题意吗!这个思维转化真的 妙(也可能是我太弱)

    (2)并查集+二分
    基于(1)的分析,我们可以借鉴01分数规划的思想进行二分,我从0~maxx(边权最大值)进行二分,在check时不使用比该点值大的边,看是否能连通起点和终点

    代码:
    最小生成树

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define I_int ll
    #define inf 0x3f3f3f3f
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    char F[200];
    inline void out(I_int x) {
        if (x == 0) return (void) (putchar('0'));
        I_int tmp = x > 0 ? x : -x;
        if (x < 0) putchar('-');
        int cnt = 0;
        while (tmp > 0) {
            F[cnt++] = tmp % 10 + '0';
            tmp /= 10;
        }
        while (cnt > 0) putchar(F[--cnt]);
        //cout<<" ";
    }
    const int maxn=1e6+7;
    struct node{
    	int a,b,w;
    	bool operator<(const node &W)const{
    		return w<W.w;
    	}
    }e[maxn];
    int root[maxn];
    int Find(int x){
    	if(root[x]!=x) root[x]=Find(root[x]);
    	return root[x];
    }
    int n,m,k;
    int u,v,w;
    bool flag;
    void Kruskal(){
    	sort(e+1,e+1+m);
    	int tot=0;
    	for(int i=1;i<=n;i++) root[i]=i;//初始化并查集
    	int res=-1,cnt=0;
    	for(int i=1;i<=m;i++){
    		int a=e[i].a,b=e[i].b,w=e[i].w;
    		a=Find(a),b=Find(b);
    		if(a!=b){
    			root[a]=b;
    		//	res=max(res,w);
    			cnt++;
    		}
    		if(Find(1)==Find(n)){
    			cout<<w<<endl;
    			flag=1;
    			break; 
    		}
    		if(cnt==n-1) break;
    	} 
    }
    void AC(){
        n=read();m=read();k=read();
        for(int i=1;i<=m;i++){
        	e[i].a=read();e[i].b=read();e[i].w=read();	
    	}
    	Kruskal();
    	if(!flag) puts("-1");
    }   
    int main(){
        AC();
        return 0;
    }
    
    
    

    并查集+二分

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define I_int ll
    #define inf 0x3f3f3f3f
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    char F[200];
    inline void out(I_int x) {
        if (x == 0) return (void) (putchar('0'));
        I_int tmp = x > 0 ? x : -x;
        if (x < 0) putchar('-');
        int cnt = 0;
        while (tmp > 0) {
            F[cnt++] = tmp % 10 + '0';
            tmp /= 10;
        }
        while (cnt > 0) putchar(F[--cnt]);
        //cout<<" ";
    }
    const int maxn=1e6+7;
    struct node{
    	int a,b,w;
    	bool operator<(const node &W)const{
    		return w<W.w;
    	}
    }e[maxn];
    int root[maxn];
    int n,m,k;
    int u,v,w;
    int maxx=-1;
    int Find(int x){
    	if(root[x]!=x) root[x]=Find(root[x]);
    	return root[x];
    }
    void init(){
    	for(int i=1;i<=n;i++) root[i]=i;
    }
    int check(int x){
    	init();
    	for(int i=1;i<=m;i++){
    		if(e[i].w>x) continue;
    		int a=Find(e[i].a),b=Find(e[i].b);
    		if(a!=b) root[b]=a;
    		if(Find(1)==Find(n)) return 1;
    	}
    	return 0;
    }
    void AC(){
        n=read();m=read();k=read();
        for(int i=1;i<=m;i++){
        	e[i].a=read();e[i].b=read();e[i].w=read();	
    		maxx=max(maxx,e[i].w);
    	}
    	//for(int i=1;i<=n;i++) root[i]=i;
    	int l=0,r=maxx,res=-1;
    	while(l<=r){
    		int mid=l+r >> 1;
    		if(check(mid)) r=mid-1,res=mid;
    		else l=mid+1; 
    	}
    	out(res);
    }   
    int main(){
        AC();
        return 0;
    }
    
    
    

    如有不足,欢迎指正~

    参考资料:
    2017-7-22 NOIP模拟赛 - Echo宝贝儿 - 博客园

  • 相关阅读:
    CSS hack:针对IE6,IE7,firefox显示不同效果
    让IE6支持png24透明/半透明的方法
    IE8的css hack
    jQuery Mobile笔记三
    jQuery Mobile笔记二
    js常见面试题
    CSS3-transform3D
    CSS3-transform-style
    CSS3-媒体类型
    CSS3-盒模型-resize属性
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853199.html
Copyright © 2020-2023  润新知