 /**//*
n<=200个点,m<=50000条边的无向图,每条边有值(gi,si)
如果某条边满足gi<=g && si <= s,则这条边可通过
现要构造出一个(g,s),使得可通过的边生成一个树,而且要使得g*G+s*S最小,G,S是给出的

我能想到的是对g排序,然后逐渐加入边,这样就限制了最大的g了
然后对已加入的边,按照s排序,从小到大枚举s,若能生成一棵树就是答案了
用并查集判断能否生成树
算错复杂度了,这样会导致O(M^2)       

看了解题报告,利用了MST的性质了 -----------------------------------OMG
“在所有生成树中的最大边,MST的最大边是最小的”
总体算法:
按g排序,每次加一条边
这样在g固定的情况下,我们目的是用最小的s来生成一棵树的
(那怎么找最小的s呢?利用上面的条件,找MST中的最大边)
所以,对每条边,将权值看成只有s,
这样如果边(u,v)连接两个连通块,则加入;
否则,加入这条边,然后寻找这个圈上的最大边,删掉
以上的操作后,肯定能生成MST,而MST上最大的边权就是我们需要的最小的s了

O(nm + mlogm)
神奇丫,加边成环删掉最大边,最后必定是MST,其上的最大权值就是我们需要的最小s了
以前只有一个边权时,排序,逐步加入即生成MST
现在,按照g排后,s不一定是有序的,需要动态生成这棵MST,就需要找圈删边了~~~
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>
#include<numeric>
#include<cassert>
#include<ctime>
#include<bitset>

using namespace std;

 struct DisjointSet {
int n;
int fa[220];

 void init(int _n) {
n = _n;
 for (int i = 0; i < n; i ++) {
fa[i] = i;
}
}
 int find_root(int a) {
return fa[a] == a ? a : fa[a] = find_root(fa[a]);
}
 bool join(int u, int v) {
u = find_root(u);
v = find_root(v);
 if(u != v) {
fa[u] = v;
return true;
}
return false;
}
};

DisjointSet ds;

 struct Edge {
int g, s, u, v;
 Edge(int u, int v, int g, int s) : u(u), v(v), g(g), s(s) {
}
};

vector<Edge> e[200];

 bool operator < (const Edge &a, const Edge &b) {
 if(a.g != b.g) {
return a.g < b.g;
}
return a.s < b.s;
}

 bool operator == (const Edge &a, const Edge &b) {
return a.u == b.u && a.v == b.v && a.g == b.g && a.s == b.s;
}

 bool cmp(const Edge &a, const Edge &b) {
return a.s < b.s;
}

 bool dfs(int p,int u, Edge &circle, Edge pe) {//找出一个圈,起点为u,并更新圈上最大边到circle,pe是父边
 if(u == p) {
return true;
}
swap(pe.u, pe.v);
 for (vector<Edge>::iterator it = e[u].begin(); it != e[u].end(); it++ ) {
 if(pe == *it) {
continue;
}
 if(dfs(p, it->v, circle, *it)) {
 if(circle.s < it->s) {
circle = *it;
}
return true;
}
}
return false;
}

int main()
  {
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif

long long G, S;
 for (int n, m; ~scanf("%d%d%I64d%I64d", &n, &m, &G, &S); ) {
vector<Edge> edges;
int u, v, g, s;
 for (int i = 0; i < m; i++) {
scanf("%d%d%d%d", &u, &v, &g, &s);
 if(u==v) {
continue;
}
u--;
v--;
edges.push_back(Edge(u,v,g,s));
}

sort(edges.begin(), edges.end());
ds.init(n);
 for (int i = 0; i < n ; i++ ) {
e[i].clear();
}
int cnt = 0;
long long ans = -1;
 for (vector<Edge>::iterator it = edges.begin(); it != edges.end(); it++) {

e[it->u].push_back(*it);
e[it->v].push_back(Edge(it->v, it->u, it->g, it->s));
 if (ds.join(it->u, it->v)) {
cnt++;
 } else {
Edge circle(*it);
dfs(it->u, it->v, circle, circle);
 for (vector<Edge>::iterator jt = e[circle.u].begin(); jt != e[circle.u].end() ; jt++) {
 if(*jt == circle) {
e[circle.u].erase(jt);
break;
}
}
swap(circle.u, circle.v);
 for (vector<Edge>::iterator jt = e[circle.u].begin(); jt != e[circle.u].end() ; jt++) {
 if(*jt == circle) {
e[circle.u].erase(jt);
break;
}
}
}

 if (cnt == n - 1) {
long long rec = 0;
 for (int i = 0; i < n ; i++ ) {
 for (vector<Edge>::iterator jt = e[i].begin(); jt != e[i].end(); jt++) {
rec = max(rec, jt->s+0LL);
}
}
rec *= S;
rec += it->g * G;
 if (ans == -1 || ans > rec) {
ans = rec;
}
}
}
printf("%I64d\n", ans);
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|