(最小生成树)Codeforces 76 A 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 are constantly plundered with bandits. After a while bandits became bored of wasting time in road robberies, so they suggested the king of Olympia to pay off. According to the offer, bandits want to get a gift consisted of gold and silver coins. Offer also contains a list of restrictions: for each road it is known gi — the smallest amount of gold and si — the smallest amount of silver coins that should be in the gift to stop robberies on the road. That is, if the gift contains a gold and b silver coins, then bandits will stop robberies on all the roads that gi ≤ a and si ≤ b.

Unfortunately kingdom treasury doesn't contain neither gold nor silver coins, but there are Olympian tugriks in it. The cost of one gold coin in tugriks is G, and the cost of one silver coin in tugriks is S. King really wants to send bandits such gift that for any two cities there will exist a safe path between them. Your task is to find the minimal cost in Olympian tugriks of the required gift.

Input

The first line of the input contains two integers N and M (2 ≤ N ≤ 200, 1 ≤ M ≤ 50 000) — the number of cities and the number of roads, respectively. The second line contains two integers G and S (1 ≤ G, S ≤ 109) — the prices of gold and silver coins in tugriks. The following M lines contain information about the offer. Each of the records in list is given as four integers xi, yi, gi, si, where xi and yi are the numbers of cities that the road connects and gisi are minimal gold and silver coins requirements for the i-th road (1 ≤ xi, yi ≤ N1 ≤ gi, si ≤ 109). Cities are numbered from 1 to N. It is possible that there are more than one road between a pair of cities. It is possible that a road connects the city with itself.

Output

The output should contain the minimal cost of the gift in Olympian tugriks. If there is no gift that satisfies the given requirements output .

Example

Input
3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1
Output
30

 

调整g值观察,注意到随着g的单调增加,s逐渐变小。故采取枚举g的值,依次建立最小生成树比较的做法,并且注意到每次增加g时只会多出一个边,即每次只可能由之前的生成树与新加的一条边来共同组成新的生成树,这样就减少了sort的过程,将新的边插入到合适的位置即可,复杂度降低了一个logm。

  1 #include <iostream>
  2 #include <string>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <queue>
  8 #include <set>
  9 #include <map>
 10 #include <list>
 11 #include <vector>
 12 #include <stack>
 13 #define mp make_pair
 14 #define MIN(a,b) (a>b?b:a)
 15 #define rank rankk
 16 //#define MAX(a,b) (a>b?a:b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 const int MAX=5e4+5;
 20 const ll INF=9223372036854775807;
 21 const int B=1024;//桶的大小
 22 const double M=4e18;
 23 using namespace std;
 24 const int MOD=1e9+7;
 25 typedef pair<int,int> pii;
 26 const double eps=0.000000001;
 27 ll maxg,maxs;
 28 int num;
 29 int n,m;
 30 /*
 31     kruskal最小生成树算法
 32     按照边的权值的顺序从小到大看一遍,如果不产生圈(重边也考虑在内)
 33     就把当前这条边加入到生成树中
 34     是否产生圈只需看两点之前是否在同一连通分量里
 35     使用并查集判断是否属于同一个连通分量
 36 */
 37 #define rank rankk  //由于与某个库名称相同,故事先define
 38 /*
 39 并查集
 40 复杂度为阿克曼函数的反函数,比O(log(n))还快
 41 */
 42 
 43 int par[MAX];//父亲
 44 int rank[MAX];//树的高度
 45 //初始化n个元素
 46 void init(int n)
 47 {
 48     for(int i=0;i<n;i++)
 49     {
 50         par[i]=i;
 51         rank[i]=0;
 52     }
 53 }
 54 //查询树的根,期间加入了路径压缩
 55 int find(int x)
 56 {
 57     if(par[x]==x)
 58         return x;
 59     else
 60         return par[x]=find(par[x]);
 61 }
 62 //合并x和y所属的集合
 63 void unite(int x,int y)
 64 {
 65     x=find(x);
 66     y=find(y);
 67     if(x==y)
 68         return ;
 69     if(rank[x]<rank[y])
 70         par[x]=y;
 71     else
 72     {
 73         par[y]=x;
 74         if(rank[x]==rank[y])
 75             rank[x]++;
 76     }
 77 }
 78 //判断x和y是否属于同一个集合
 79 bool same(int x,int y)
 80 {
 81     return find(x)==find(y);
 82 }
 83 /*
 84 建立结构体记录边
 85 */
 86 struct edge
 87 {
 88     int u,v;
 89     ll cost,cost2;
 90 };
 91 bool cmp(const edge &e1,const edge &e2)
 92 {
 93     if(e1.cost!=e2.cost)
 94         return e1.cost<e2.cost;
 95     else
 96         return e1.cost2<e2.cost2;
 97 }
 98 bool cmp2(const edge &e1,const edge &e2)
 99 {
100     if(e1.cost2!=e2.cost2)
101         return e1.cost2<e2.cost2;
102     else
103         return e1.cost<e2.cost;
104 }
105 bool kruskal(edge *e,int vertice_num)//e为存储边的数组,下标从0开始
106 {
107     maxg=maxs=0LL;
108     init(n+2);//初始化并查集
109     num=0;
110     for(int i=1;i<=vertice_num;i++)
111     {
112         edge tem=e[i];
113         if(!same(tem.u,tem.v))
114         {
115             unite(tem.u,tem.v);
116             e[++num]=e[i];
117             maxg=max(maxg,e[i].cost);
118             maxs=max(maxs,e[i].cost2);
119             if(num==n-1)
120                 break;
121         }
122     }
123     if(num==n-1)
124         return true;
125     else
126         return false;
127 }
128 edge es[MAX];
129 ll g,s,an;
130 int main()
131 {
132     while(~scanf("%d%d",&n,&m))
133     {
134         an=INF;
135 //        scanf("%lld%lld",&g,&s);
136         scanf("%I64d%I64d",&g,&s);
137         for(int i=1;i<=m;i++)
138         {
139 //            scanf("%d%d%lld%lld",&es[i].u,&es[i].v,&es[i].cost,&es[i].cost2);
140             scanf("%d%d%I64d%I64d",&es[i].u,&es[i].v,&es[i].cost,&es[i].cost2);
141         }
142         sort(es+1,es+1+m,cmp);
143 //        sort(es+1,es+1+n-1,cmp2);
144 //        if(kruskal(es,n-1))
145 //            an=min(an,maxg*g+maxs*s);
146 
147         for(int i=1;i<=m;i++)
148         {
149 //            es[i<=n?i:n]=es[i];
150 //            int j=(i<=n?i-1:n-1);
151             es[++num]=es[i];
152             int j=num-1;
153             while(j&&es[j].cost2>es[j+1].cost2)
154             {
155                 swap(es[j],es[j+1]);
156                 --j;
157             }
158             if(kruskal(es,num))
159                 an=min(an,maxg*g+maxs*s);
160         }
161         if(an==INF)
162             printf("-1\n");
163         else
164 //            printf("%lld\n",an);
165             printf("%I64d\n",an);
166     }
167 
168 }

 

转载于:https://www.cnblogs.com/quintessence/p/6906538.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园建设是在国家政策推动下,为深化教育改革、提升教育质量和管理效率而提出的重要项目。该项目旨在通过信息化手段,解决传统教育中存在的资源分散、管理混乱等问题,实现教育资源的高效利用和教学质量的全面提升。 目前,教育信息化虽取得一定进展,但面临“孤岛架构”的挑战,包括硬件资源无法共享、数据孤岛、应用孤岛等问题,导致资源浪费和管理效率低下。为此,智慧校园的建设目标聚焦于家校沟通便捷化、校园管理科学化、校园生活轻松化、课堂教学互动化和校园设施智能化,以提高教学效率和学生学习体验。 智慧校园的核心价值在于构建先进的网络教学平台和管理信息系统,实现教学资源的高效配置和利用,促进师生互动,提高管理效率,降低成本,构建健康高雅的生活环境。解决方案涵盖综合应用平台规划、系统架构设计、媒体发布、数字会议系统等,通过后台服务层、基础接入层和用户接入层的有机结合,实现智慧校园的全面功能。 智慧校园管理平台作为核心组成部分,提供模块化体系,包括公开课、直播、教学资源等23大应用,支持与第三方接口对接,实现多级管理。电教预约管理平台通过移动端APP或web后台简化预约流程,提高教室和会议室资源利用率,支持会议预订、审批、信息发布和环境管控。 教育录播系统和云平台支持教师制作和分享优质教学资源,进行在线组卷和评卷,同时提供学生应用,如高清视频录制、在线直播和互动交流,促进教学资源的共享和教育均衡化发展。这些系统的整合应用,将极大地推动教育信息化进程,实现教育资源的最大化利用和教育质量的全面提升。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值