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

简介: 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宝贝儿 - 博客园

目录
相关文章
|
1月前
|
人工智能 BI
【每日一题Day267】LC834树中距离之和 | 换根dp
【每日一题Day267】LC834树中距离之和 | 换根dp
27 0
|
30天前
|
Java
POJ- 2367- Genealogical tree【拓扑排序】
POJ- 2367- Genealogical tree【拓扑排序】
8 0
|
8月前
|
存储 容器
华为机试HJ41:称砝码(深度优先遍历dfs-Depth First Search)
华为机试HJ41:称砝码(深度优先遍历dfs-Depth First Search)
|
10月前
|
人工智能
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
AtCoder Beginner Contest 216 D - Pair of Balls (思维建图 拓扑排序判断有向图是否有环)
97 0
|
定位技术
UPC——帕琪的药园(dfs或并查集)
UPC——帕琪的药园(dfs或并查集)
60 0
codeforces1253——D. Harmonious Graph(并查集)
codeforces1253——D. Harmonious Graph(并查集)
74 0
[Nowcoder] network | Tarjan 边双连通分量 | 缩点 | LCA倍增优化 | 并查集
题目描述 A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers are connected directly or indirectly by successive links, so data can be transformed between any two computers.
110 0
[Nowcoder] network | Tarjan 边双连通分量 | 缩点 | LCA倍增优化 | 并查集
|
人工智能 BI Go
[Atcoder ABC222] F - Expensive Expense | 妙用树的直径 | Dijkstra
Problem Statement The Kingdom of AtCoder is composed of N towns and N−1 roads. The towns are labeled as Town 1, Town 2, …, Town N. Similarly, the roads are labeled as Road 1, Road 2, …, Road N−1. Road i connects Towns Ai and Bi bidirectionally, and you have to pay the toll of Ci to go through it.
187 0
[Atcoder ABC222] F - Expensive Expense | 妙用树的直径 | Dijkstra
|
人工智能 Prometheus Cloud Native
牛客第五场 B Graph最小异或生成树
这道题涉及到最小异或生成树,要理解这个首先要明白 01字典树 关于01字典树呢,先来一道板子题hdu4825 ==》 不方便跳转的同学们可以看下面的题 Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。
109 0
牛客第五场 B Graph最小异或生成树