CodeForces - 76A:Gift (最小生成树 解决单调性问题是思想)

题意:给定N点M边的无向连通图,每条边有两个权值(g,s)。 给定G,S。 让你给出一组(g0,s0)使得图中仅留下g<=g0, s<=s0的边之后,依然连通,并求Gg0+Ss0的最小值。 n<=200,m<=50000。

思路:枚举g0,求最小的s0,满足生成MST。 把边按g排序,一条边一条边的加入,然后在加入边的集合里面找出最小的s。但是每次排序复杂度过高,而且边数也过多,(LCT做也行吧,就不需要考虑这么多)。 我们去优化暴力的做法。假设新加入一条边,显然最多改变一条边,那么我们维护一个有序序列,表示MST用的边(N-1条),新加入后,手动排序(O(N)),然后把这N条边建立新的MST,就可以了。

#include<bits/stdc++.h>
#define ll long long
#define pair<ll,ll> pii
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
struct in{
    int u,v;ll a,b;
}s[maxn];
bool cmp(in p,in q){
    if(p.a!=q.a) return p.a<q.a;
    return p.b<q.b;
}
int fa[maxn],q[maxn];
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
int main()
{
    int N,M,tot=0;  ll G,S,A=0,B=0,ans=-1;
    scanf("%d%d%lld%lld",&N,&M,&G,&S);
    rep(i,1,M){
        scanf("%d%d%lld%lld",&s[i].u,&s[i].v,&s[i].a,&s[i].b);
        if(s[i].u==s[i].v) i--,M--;
    }
    sort(s+1,s+M+1,cmp);
    rep(i,1,M){
        q[++tot]=i; int t=tot;
        while(t>1&&s[q[t]].b<s[q[t-1]].b) swap(q[t],q[t-1]),t--;
        rep(j,1,N) fa[j]=j; tot=0;
        rep(j,1,N) {
            int fu=find(s[q[j]].u);
            int fv=find(s[q[j]].v);
            if(fu==fv) continue;
            fa[fu]=fv;
            q[++tot]=q[j];
            if(tot==N-1) break;
        }
        if(tot==N-1){
            if(ans==-1) ans=G*s[i].a+S*s[q[N-1]].b;
            else ans=min(ans,G*s[i].a+S*s[q[N-1]].b);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/11184981.html

时间: 2024-10-08 21:05:33

CodeForces - 76A:Gift (最小生成树 解决单调性问题是思想)的相关文章

CodeForces 76A Gift - 最小生成树

The kingdom of Olympia consists of N cities and M bidirectional roads. Each road connects exactly two cities and two cities can be connected with more than one road. Also it possible that some roads connect city with itself making a loop. All roads a

CodeForces 141E: ...(最小生成树)

[条件转换] 两两之间有且只有一条简单路径<==>树 题意:一个图中有两种边,求一棵生成树,使得这棵树中的两种边数量相等. 思路: 可以证明,当边的权是0或1时,可以生成最小生成树到最大生成树之间的任意值的生成树. 那么,方法就是生成最小生成树,然后,尽量替换0边,使得其成为值为(n-1)/2的生成树. 代码: 写的很乱,没有条理.还是应当先写出流程伪码后再敲代码的. #include <cstdio> #include <cstring> #include <v

利用Kruskal算法求最小生成树解决聪明的猴子问题 -- 数据结构

题目:聪明的猴子 链接:https://ac.nowcoder.com/acm/problem/19964 在一个热带雨林中生存着一群猴子,它们以树上的果子为生.昨天下了一场大雨,现在雨过天晴,但整个雨林的地 表还是被大水淹没着,部分植物的树冠露在水面上.猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面 的不同树冠上来回穿梭,以找到喜欢吃的果实.现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都 很小,可以忽略不计.我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表

最小生成树的Prime算法的思想

普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现:1959年,艾兹格·迪科斯彻再次发现了该算法.因此,在某些场合,普里姆算法又被称为D

用DFS 解决全排列问题的思想详解

首先考虑一道奥数题目: □□□ + □□□ = □□□,要将数字1~9分别填入9个□中,使得等式成立.例如173+286 = 459.请输出所有合理的组合的个数. 我们或许可以枚举每一位上所有的数,然后判断每一位上的数需要互不相等且满足等式即可,但是用代码写出来需要声明9个变量且判断. 那么我们把这个问题考虑为一个求这个9个数的全排列问题,即可得到更优雅的解答方式. 首先我们考虑一个经典的全排列问题(<啊哈,算法>): 输入一个数,输出1~n的全排列. 现在我们考虑有1.2.3的3张扑克牌和编

Codeforces 383C Propagating tree, 线段树, 黑白染色思想

按深度染色,奇深度的点存反权值. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 vector <int> g[500005]; 5 int t1,t2,t3,seq[500005],a[1000005],s[500005],vis[500005],ind,n,m,src[500005],frm[500005],dep[500005]; 6 7 void dfs(int p) { 8 vis[p]=1; 9 frm[p]=

CodeForces 828C String Reconstruction(并查集思想)

题意:给你n个串,给你每个串在总串中开始的每个位置,问你最小字典序总串. 思路:显然这道题有很多重复填涂的地方,那么这里的时间花费就会特别高. 我们维护一个并查集fa,用fa[i]记录从第i位置开始第一个没填涂的位置,那每次都能跳过涂过的地方.每次填完当前格就去填find(fa[i + 1]). ps:一定要合并,不然超时. 代码: #include<stack> #include<vector> #include<queue> #include<set>

CF 160D Edges in MST 最小生成树的性质,寻桥,缩点,批量处理 难度:3

http://codeforces.com/problemset/problem/160/D 这道题要求哪条边存在于某个最小生成树中,哪条边不存在于最小生成树中,哪条边绝对存在于最小生成树中 明显桥边一定存在于所有最小生成树中,然而怎么处理存在某个最小生成树的边呢? 借助kruskal算法的性质,由小到大,每次处理同一权值的边,如果边连接的点已经联通就不要管,否则那些处理的边一定存在于某最小生成树上 批量处理的思想很巧妙 #include <cstdio> #include <vecto

树的问题小结(最小生成树、次小生成树、最小树形图、LCA、最小支配集、最小点覆盖、最大独立集)

树的定义:连通无回路的无向图是一棵树. 有关树的问题: 1.最小生成树. 2.次小生成树. 3.有向图的最小树形图. 4.LCA(树上两点的最近公共祖先). 5.树的最小支配集.最小点覆盖.最大独立集. 一.最小生成树 解决的问题是:求无向图中边权值之和最小的生成树. 算法有Kruskal和Prim. Kruskal使用前向星和并查集实现,可以存储重边(平行边),时间复杂度是O(m log m  +  m),m是边的数量. Prim使用邻接矩阵建图,不可以存储重边(平行边),如果出现重边,存储的