上午思维题训练
https://codeforces.com/contest/2026/problem/C
https://codeforces.com/contest/2026/problem/B
https://codeforces.com/contest/2023/problem/A
https://codeforces.com/contest/2034/problem/D
下午
https://vjudge.net/problem/HDU-4612
题意:有一个无向图,加一条无向边使得这个图的割边最小。
思路:通过eDcc缩点,缩成一棵树,然后求树的直径,答案就是割边-树的直径
思路AC,代码没有AC,一直MLE,日后再改。
#include <bits/stdc++.h>
//#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=2e4+10,M=1e6+10,inf=1e16,mod=1e8;
int n,m;
struct edge{
int v,last;
}e[M];
int h[N],idx;//0开始
vector<int> fir;
void add(int u,int v) {
fir.push_back(u);
e[idx].v=v;
e[idx].last=h[u];
h[u] = idx++;
}
int dfn[N],low[N],tot;
stack<int> stk;
int dcc[N],cnt;//dcc记录边双连通分量
int bri[M];//bri[i]记录割边
void tarjan(int x,int edg) {
dfn[x] = low[x] = ++tot;
stk.push(x);
for (int i = h[x]; ~i; i = e[i].last) {
int y = e[i].v;
if (!dfn[y]) {
tarjan(y, i);
low[x] = min(low[y], low[x]);
if (low[y] > dfn[x]) {//割边
bri[i] = 1;
bri[i ^ 1] = 1;
}
} else if (i != (edg ^ 1)) {
low[x] = min(dfn[y], low[x]);
}
}
//离,判边双连通分量
if (dfn[x] == low[x]) {
++cnt;
while (1) {
int y = stk.top();
stk.pop();
dcc[y] = cnt;
if (x == y) break;
}
}
}
vector<int> ne[N];
int ans=0;
int dfs(int u,int f){
int d1=0,d2=0;
for(auto v:ne[u]){
if(v==f) continue;
int d=dfs(v,u)+1;
if(d>d1) d2=d1,d1=d;
else if(d>d2) d2=d;
}
ans=max(ans,d1+d2);
return d1;
}
void solve() {
while(cin>>n>>m){
if(n==0&&m==0) break;
idx=tot=cnt=ans=0;
for(int i=0;i<=n;i++) {
dfn[i]=low[i]=0;
h[i]=-1;
dcc[i]=0;
ne[i].clear();
}
while(!stk.empty()) stk.pop();
for(int i=0;i<=m;i++){
e[i].v=-1,e[i].last=-1;
bri[i]=0;
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++){
if(!dfn[i]) tarjan(i,-1);
}
for(int i=0;i<idx;i++){
if(bri[i]){
ne[dcc[fir[i]]].push_back(dcc[e[i].v]);
}
}
dfs(1,-1);
cout<<cnt-1-ans<<endl;
}
}
signed main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
// int _;
// cin >> _;
// while (_--)
solve();
return 0;
}
畅通工程再续 - HDU 1875 - Virtual Judge
这题比较典,数据较小,所以暴力建边,然后并查集求最小生成树。
#include <bits/stdc++.h>
//#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=105,M=1e6+10,inf=1e16,mod=1e8;
double dis[105][105];
int fa[N];
struct node {
double x, y;
};
double f(node a,node b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct node1 {
int u, v;
double w;
}e[M];
int find(int x) {
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void solve() {
int n;
cin >> n;
vector<node> v;
v.push_back({0, 0});
for (int i = 1; i <= n; i++) {
double x, y;
cin >> x >> y;
v.push_back({x, y});
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) {
dis[j][i] = f(v[j], v[i]);
++cnt;
e[cnt].u = j, e[cnt].v = i, e[cnt].w = dis[j][i];
}
}
auto cmp = [&](node1 a, node1 b) {
return a.w < b.w;
};
double ans = 0;
for (int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1, e + cnt + 1, cmp);
auto kruscal = [&]() {
int num = 0;
for (int i = 1; i <= cnt; i++) {
if (e[i].w > 1000) break;
if (e[i].w < 10) continue;
int x = find(e[i].u);
int y = find(e[i].v);
if (x != y) {
fa[x] = y;
ans += e[i].w;
num++;
}
}
return num == n - 1;
};
if (kruscal()) printf("%.1lf\n", ans * 100);
else cout << "oh!" << endl;
}
signed main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _;
cin >> _;
while (_--)
solve();
return 0;
}
[P1967 NOIP2013 提高组] 货车运输 - 洛谷 | 计算机科学教育新生态
题意:有一个带权无向图,现在询问图上任意两点的所有路径中最大的边权
思路:要求最大边权,所以,可想而知,图上有些小边权是用不上的,所以要去掉一些边,首先建最大生成树,
然后在最大生成树上求任意两点的路径最大边权,倍增求LCA的时候,可以求出树上俩点的路径,是在图上向上跳,递推而来的,同样,所以求最大边权可以求LCA得来。
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=3e4+10,M=5e4+10,inf=1e16,mod=1e8;
int fa[N],dfn[N],dep[N];
int Fa[N][25],dis[N][25],tot;
int n,m;
struct edge {
int u, v, w;
bool operator<(const edge &t) const {
return w > t.w;
}
}e[M];
struct node {
int v, w;
};
vector<node> ne[N];
int find(int x) {
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
void kruscal() {
for (int i = 1; i <= m; i++) {
int x = find(e[i].u), y = find(e[i].v);
if (x != y) {
fa[x] = y;
ne[e[i].u].push_back({e[i].v, e[i].w});
ne[e[i].v].push_back({e[i].u, e[i].w});
}
}
}
void dfs(int now,int f) {
dep[now] = dep[f] + 1;
dfn[now] = ++tot;
Fa[now][0] = f;
for (int i = 0; i <= 21; i++) {
Fa[now][i + 1] = Fa[Fa[now][i]][i];
if (dfn[Fa[now][i + 1]]) dis[now][i + 1] = min(dis[now][i], dis[Fa[now][i]][i]);
}
for (auto k: ne[now]) {
int v = k.v, w = k.w;
if (v != f) {
dis[v][0] = w;
dfs(v, now);
}
}
}
int lca(int x,int y) {
int ans = 1e16;
if (dep[x] < dep[y]) swap(x, y);
for (int i = 22; i >= 0; i--) {
if (dep[Fa[x][i]] >= dep[y]) ans = min(ans, dis[x][i]), x = Fa[x][i];
}
if (x == y) return ans;
for (int i = 22; i >= 0; i--) {
if (Fa[x][i] != Fa[y][i]) {
ans = min(ans, min(dis[x][i], dis[y][i]));
x = Fa[x][i], y = Fa[y][i];
}
}
ans = min(ans, min(dis[x][0], dis[y][0]));
return ans;
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> e[i].u >> e[i].v >> e[i].w;
}
for (int i = 1; i <= n; i++) fa[i] = i;
sort(e + 1, e + m + 1);
kruscal();
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= 22; j++) dis[i][j] = 1e16;
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) dis[i][0] = 1e16, dfs(i, 0);
}
int q;
cin >> q;
while (q--) {
int x, y;
cin >> x >> y;
if (find(x) != find(y)) {
cout << -1 << endl;
continue;
}
cout << lca(x, y) << endl;
}
}
signed main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
// int _;
// cin >> _;
// while (_--)
solve();
return 0;
}
标签:,return,int,fa,low,ans,find
From: https://www.cnblogs.com/Cakefish/p/18658292