题解
F - Built?
题意
平面上有
N
N
N个城市。第
i
i
i个城市的坐标为
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi)(
x
,
y
x,y
x,y均为整数)同一个坐标上可能有多个城市。在坐标为
(
a
,
b
)
(a,b)
(a,b)的城市和坐标为
(
c
,
d
)
(c,d)
(c,d)的城市间建造一条道路需要
m
i
n
(
∣
a
−
c
∣
,
∣
b
−
d
∣
)
min(∣a−c∣,∣b−d∣)
min(∣a−c∣,∣b−d∣)元。只能在城市与城市间建造道路。 要使任意两个城市之间有直接或间接道路相连,最少需要多少元?
2
≤
N
≤
1
0
5
,
0
≤
x
i
,
y
i
≤
1
0
9
2≤N≤10^5,0≤x_i ,y_i ≤10^9
2≤N≤105,0≤xi,yi≤109
思路
题目是最小生成树,但是N的范围较大,暴力建边显然会超时。
观察到每一条边的长度是两点
x
x
x之差和
y
y
y之差的最小值,可以将
x
x
x之差和
y
y
y之差分开建边,这样
N
N
N个城市按
x
x
x,
y
y
y大小排序后建边只需建
2
(
N
−
1
)
2(N-1)
2(N−1)条边即可。
建完边后只需用喜欢的最小生成树算法做即可。
代码
#include <bits/stdc++.h>
using namespace std;
int fa[100005];
int fa_find(int x)
{
if (fa[x] == x)
return x;
else
return fa[x] = fa_find(fa[x]);
}
void fa_add(int x, int y)
{
fa[fa_find(x)] = fa_find(y);
}
struct edge
{
int x, y, v;
}e[100005], ae[200005];
int cmpx(edge a, edge b)
{
return a.x < b.x;
}
int cmpy(edge a, edge b)
{
return a.y < b.y;
}
int cmpv(edge a, edge b)
{
return a.v < b.v;
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i <= n; i++)
fa[i] = i;
for (int i = 1; i <= n; i++)
{
e[i].v = i;
scanf("%d%d", &e[i].x, &e[i].y);
}
sort(e + 1, e + n + 1, cmpx);
for (int i = 1; i < n; i++)
{
ae[i].x = e[i].v;
ae[i].y = e[i + 1].v;
ae[i].v = e[i + 1].x - e[i].x;
}
sort(e + 1, e + n + 1, cmpy);
for (int i = 1; i < n; i++)
{
ae[i + n - 1].x = e[i].v;
ae[i + n - 1].y = e[i + 1].v;
ae[i + n - 1].v = e[i + 1].y - e[i].y;
}
sort(ae + 1, ae + 2 * n - 1, cmpv);//Kruskal
long long ans = 0;
for (int i = 1; i < 2 * n - 1; i++)
if (fa_find(ae[i].x) != fa_find(ae[i].y))
{
fa_add(ae[i].x, ae[i].y);
ans += ae[i].v;
}
printf("%lld\n", ans);
return 0;
}
I - 单源最短路
题意
给一个
n
n
n个点
m
m
m条边的无向图,求
s
s
s点到
t
t
t点的最短路。
1
≤
n
≤
2500
,
1
≤
m
≤
6200
,
1
≤
s
,
t
≤
n
1≤n≤2500,1≤m≤6200,1≤s,t≤n
1≤n≤2500,1≤m≤6200,1≤s,t≤n
思路
单源最短路模板题。题目数据量小,用邻接表+spfa解决。
代码
#include <bits/stdc++.h>
using namespace std;
int n, m, s, t;
const int maxn = 2505;
const int maxm = 6205;
int vis[maxn] = { 0 };
long long dis[maxn];
vector<pair<int,int>> e[maxn];//邻接表
void spfa()
{
for (int i = 1; i <= n; i++)
dis[i] = INT64_MAX;//s到i点距离初始化
deque<int> list;//STL的双向队列
list.push_back(s), dis[s] = 0, vis[s] = 1;//出发点入队
while (!list.empty())
{
int x = list[0];
for (int i = 0; i < e[x].size(); i++)
{
int nx = e[x][i].first, nd = e[x][i].second;
if (dis[nx] > dis[x] + nd)//如果有最短路就更改
{
dis[nx] = dis[x] + nd;
if (vis[nx] == 0)//未入队则入队
{
vis[nx] = 1;//标记入队
list.push_back(nx);
}
}
}
list.pop_front();
vis[x] = 0;//标记出队
}
return;
}
int main()
{
cin >> n >> m >> s >> t;
for (int i = 0; i < m; i++)
{
int x, y, d;
scanf("%d%d%d", &x, &y, &d);
e[x].push_back(make_pair(y, d));
e[y].push_back(make_pair(x, d));//无向图双向建边
}
spfa();
cout << dis[t];
return 0;
}
N - Cat VS Dog
题意
有
N
N
N只猫和
M
M
M只狗,还有
P
P
P个投票者,每一个投票者会选择投票一只猫留下并且一只狗淘汰或一只狗留下并且一只猫淘汰,求最多可以使多少个投票者的想法得到满足(即自己喜欢的猫(狗)留了下来且讨厌的狗(猫)被淘汰)。
多组数据输入,
N
<
=
100
,
M
<
=
100
,
P
<
=
500.
多组数据输入,N <= 100, M <= 100 ,P <= 500.
多组数据输入,N<=100,M<=100,P<=500.
思路
首先可以看出,投票者分为两种,喜欢猫的人和喜欢狗的人,两种人构成了一个二分图。一个喜欢人某只猫(狗)而另一个人讨厌这只猫(狗),这两个人的想法不可能同时满足。我们考虑将这两个人建边,计算这个这个二分图的最大独立集,集中的便是可以被满足的最多的人。
二分图最大独立集等于总点数减最大点匹配,可以使用匈牙利算法计算二分图最大点匹配。
代码
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define maxn 505
vector<int> e[maxn];
int vis[maxn], match[maxn];
//标准的最大点匹配
bool dfs(int x, int flag) {
for (int i = 0; i < e[x].size(); ++i) {
int nx = e[x][i];
if (vis[nx] != flag) {
vis[nx] = flag;
if (!match[nx] || dfs(match[nx], flag)) {
match[nx] = x;
return 1;
}
}
}
return 0;
}
int main()
{
int c, d, v;
while (cin >> c >> d >> v)
{
vector<int> Plc, Pld;
int vC[maxn], vD[maxn];
for (int i = 1; i <= v; i++)
{
e[i].clear();
char a, b;
int x, y;
cin >> a >> x >> b >> y;
if (a == 'C')
{
Plc.push_back(i);//喜欢猫的人
vC[i] = x;
vD[i] = y;
}
else
{
Pld.push_back(i);//喜欢狗的人
vC[i] = y;
vD[i] = x;
}
}
//喜欢猫的人和喜欢狗的人一一比较是否冲突
for (int i = 0; i < Plc.size(); i++)
{
for (int j = 0; j < Pld.size(); j++)
{
int x = Plc[i], y = Pld[j];
if (vC[x] == vC[y] || vD[x] == vD[y])
e[x].push_back(y);
}
}
int ans = v;
memset(match, 0, sizeof(match));
memset(vis, 0, sizeof(vis));//每次vis数组存在的检测都改变,避免反复memset浪费时间
for (int i = 0; i < Plc.size(); i++)
if (dfs(Plc[i], i + 1)) ans--;
cout << ans << endl;
}
return 0;
}