(最小生成树)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 gi, si are minimal gold and silver coins requirements for the i-th road (1 ≤ xi, yi ≤ N, 1 ≤ 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
3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1
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 }