随便说点:
博主正在刷kuangbin专题的题目,初学者,没接触过什么算法,刷题的初衷是备战蓝桥杯,后来发现了算法资料大多是针对acm的,挑选kuangbin专题入门也是如此,毕竟这样分类看起来比较有目的的刷题。
所以有的代码比较冗余,越往后面的题解代码变化越大,
代码的风格和算法思想也是在一步步的学习和进步,多多包容,互相借鉴。
建议做题顺序:
做最小生成树专题没最短路和并查集专题时那么吃力,题目难度有下降。所以把题解都整合在一篇博客里
最小生成树基础:1 2 4 5 6 9 12 14
最小生成树应用:10 3 8 7
这是我做完一遍之后觉得比较好的做题顺序,由易到难,相同类型题放在一起加深理解。
把字符转化成整型,然后套用模板
//poj1251
#include
#include
#include
using namespace std;
const int N = 28, INF = 0x3f3f3f3f;
int maps[N][N],visit[N];
int d[N];
int n;
int prim()
{
int ans = 0;
for (int i = 1; i < n; i++)
d[i] = maps[0][i];
d[0] = 0;
for (int i = 1; i < n; i++)
{
int t = -1;
for (int j = 1; j < n; j++)
{
if (!visit[j])
if (d[j] < d[t] || t == -1)
t = j;
}
visit[t] = 1;
ans += d[t];
for (int j = 1; j < n; j++)
if (!visit[j])
d[j] = min(d[j], maps[t][j]);
}
return ans;
}
int main()
{
while (~scanf("%d", &n),n)
{
memset(maps, 0x3f, sizeof(maps));
memset(visit, 0, sizeof(visit));
for (int i = 0; i < n-1; i++)
{
char u;
int t;
scanf(" %c %d", &u, &t);
while (t--)
{
char v;
int w;
scanf(" %c %d", &v,&w);
maps[i][v - 'A'] = w;
maps[v - 'A'][i] = w;
}
}
printf("%d\n", prim());
}
return 0;
}
模板题
#include
#include
#include
using namespace std;
const int N = 55, INF = 0x3f3f3f3f;
int maps[N][N],visit[N];
int d[N];
int n, m;
int prim()
{
int ans = 0;
for (int i = 2; i <= n; i++)
d[i] = maps[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[j] < d[t] || t == -1)
t = j;
}
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j])
d[j] = min(d[j], maps[t][j]);
}
return ans;
}
int main()
{
while (~scanf("%d%d", &n, &m), n)
{
memset(maps, 0x3f, sizeof(maps));
memset(visit, 0, sizeof(visit));
for (int i = 0; i < m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
if (w < maps[u][v]) {
maps[u][v] = w;
maps[v][u] = w;
}
}
printf("%d\n", prim());
}
return 0;
}
prim,注意 若两圆心距离-半径之和< =0则两点权值设置为0
#include
#include
#include
#include
using namespace std;
const int N = 105;
const double INF = 1e15;
int visit[N];
double d[N];
int n,m;
struct node {
double x, y, z, r;
}maps[N];
double getDis(double x1, double y1,double z1, double x2, double y2, double z2 )
{
return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)+ (z1 - z2)*(z1 - z2));
}
double prim()
{
memset(visit, 0, sizeof(visit));
for (int i = 1; i <= n; i++)
d[i] = INF;
double ans = 0;
for (int i = 2; i <= n; i++) {
double len = getDis(maps[1].x, maps[1].y, maps[1].z, maps[i].x, maps[i].y, maps[i].z);
double r = maps[1].r+ maps[i].r;
if (r >= len) d[i] = 0;
else d[i] = len-r;
}
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[t] > d[j]|| t == -1)
t = j;
}
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j]) {
double len = getDis(maps[t].x, maps[t].y, maps[t].z, maps[j].x, maps[j].y, maps[j].z);
double r = maps[t].r + maps[j].r;
if (r >= len)len = 0;
else len = len - r;
d[j] = min(d[j], len);
}
}
return ans;
}
int main()
{
while (scanf("%d", &n),n)
{
for (int i = 1; i <= n; i++)
scanf("%lf%lf%lf%lf", &maps[i].x, &maps[i].y, &maps[i].z, &maps[i].r);
printf("%.3lf\n", prim());
}
return 0;
}
模板题
//poj2421
#include
#include
#include
#include
using namespace std;
const int N = 105;
const int M = N * N;
const double INF = 1e15;
int fa[N];
int n, m, cnt = 0;;
struct Node {
int u, v, w;
bool operator < (const Node& a) const {
return w < a.w;
}
}e[M];
int find(int x)
{
return fa[x] == -1 ? x : fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx == fy)return;
fa[fy] = fx;
}
int kustral()
{
sort(e, e + n * n);
int ans = 0;
for (int i = 0; i <cnt; ++i) {
if (e[i].u == e[i].v)continue;
if (find(e[i].u) != find(e[i].v)) {
unite(e[i].u, e[i].v);
ans += e[i].w;
}
}
return ans;
}
int main()
{
while (~scanf("%d", &n))
{
memset(fa, -1, sizeof(fa));
cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
scanf("%d", &e[cnt].w);
e[cnt].u = i, e[cnt].v = j;
cnt++;
}
scanf("%d", &m);
for (int j = 0; j < m; j++)
{
int u, v;
scanf("%d%d", &u, &v);
unite(u, v);
}
printf("%d\n", kustral());
}
return 0;
}
模板题,边的权值=各自的适配器+道路的花费
//zoj 1586
#include
#include
#include
#include
using namespace std;
const int N = 1e3+10;
int visit[N];
int maps[N][N];
int qsNode[N];
int d[N];
int n;
int prim()
{
int ans = 0;
memset(visit, 0, sizeof(visit));
for (int i = 2; i <= n; i++)
d[i] = maps[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[t] > d[j] || t == -1)
t = j;
}
if (t == -1)break;
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j]) {
d[j] = min(maps[t][j], d[j]);
}
}
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &qsNode[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
scanf("%d", &maps[i][j]);
maps[i][j] = maps[i][j] + qsNode[i] + qsNode[j];
}
printf("%d\n", prim());
}
return 0;
}
处理一下图,边的权值为两个字符串对应位置字母不同的个数
然后套用模板即可。
//poj1789
#include
#include
#include
#include
using namespace std;
const int N = 2e3+10;
int visit[N];
char str[N][8];
int maps[N][N];
int d[N];
int n;
int prim()
{
int ans = 0;
memset(visit, 0, sizeof(visit));
for (int i = 2; i <= n; i++)
d[i] = maps[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[t] > d[j] || t == -1)
t = j;
}
if (t == -1)break;
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j]) {
d[j] = min(maps[t][j], d[j]);
}
}
return ans;
}
int main()
{
while (scanf("%d", &n),n)
{
for (int i = 1; i <= n; i++)
scanf("%s", str[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (i == j)maps[i][j] = 0;
else {
int cnt = 0;
for (int k = 0; k < 7; k++)
if (str[i][k] != str[j][k])cnt++;
maps[i][j] = maps[j][i] = cnt;
}
}
printf("The highest possible quality is 1/%d.\n", prim());
}
return 0;
}
因为n个卫星可以同时使得n-1条边免费,故还是kustral
把边排序,最小生成树,记录每次加入的边值,最后输出倒数第m条边即可,m = 免费的边数+1。
即不算后面n-1条免费的边
//poj2349
#include
#include
#include
#include
using namespace std;
const int N = 505;
const int M = N * N;
const double INF = 1e15;
int fa[N];
int n, m, cnt = 0;
struct Node {
int u, v;
double w;
bool operator < (const Node& a) const {
return w < a.w;
}
}e[M];
typedef pair<int, int> pp;
pp point[N];
int find(int x)
{
return fa[x] == -1 ? x : fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
int fx = find(x), fy = find(y);
if (fx == fy)return;
fa[fy] = fx;
}
double getDis(double x1, double y1, double x2, double y2)
{
return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
double kustral()
{
sort(e, e + n * (n-1));
double ans[N];
int index = 0;
for (int i = 0; i < cnt; ++i) {
if (e[i].u == e[i].v)continue;
if (find(e[i].u) != find(e[i].v)) {
unite(e[i].u, e[i].v);
ans[index] = e[i].w;
index++;
}
}
index = index - m;
return ans[index];
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &m, &n);
memset(fa, -1, sizeof(fa));
for (int i = 1; i <= n; i++)
scanf("%d%d", &point[i].first, &point[i].second);
cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (i == j)continue;
e[cnt].u = i, e[cnt].v = j;
e[cnt].w = getDis(point[i].first, point[i].second, point[j].first, point[j].second);
cnt++;
}
printf("%.2lf\n", kustral());
}
return 0;
}
prim,注意已经存在的边权值设置为0,还有就是输出边时涉及边的两点,可以把d[]数组定义成结构体数组,更新边的权值时顺便记录下是被哪个点更新的。
//poj1751
#include
#include
#include
#include
using namespace std;
const int N = 760, M = 1010;
const double INF = 1e15;
int visit[N];
bool isFree[N][N];
int n, m;
struct node {
int x, y;
}maps[N];
struct node2 {
int u;
double dis;
}d[M];
double getDis(double x1, double y1, double x2, double y2)
{
return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
void prim()
{
memset(visit, 0, sizeof(visit));
for (int i = 1; i <= n; i++)
d[i].dis = INF;
for (int i = 2; i <= n; i++) {
if (isFree[1][i]) {
d[i].dis = 0;
}
else {
d[i].dis = getDis(maps[1].x, maps[1].y, maps[i].x, maps[i].y);
d[i].u = 1;
}
}
d[1].dis = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j] && d[j].dis != INF)
if (d[t].dis > d[j].dis || t == -1)
t = j;
}
visit[t] = 1;
if (t == -1)break;
if (d[t].dis != 0 && d[t].dis != INF) {
printf("%d %d\n", d[t].u, t);
}
for (int j = 2; j <= n; j++)
if (!visit[j]) {
double len;
if (isFree[t][j])len = 0;
else {
len = getDis(maps[t].x, maps[t].y, maps[j].x, maps[j].y);
}
if (d[j].dis > len) {
d[j].dis = len;
d[j].u = t;
}
}
}
}
int main()
{
while (~scanf("%d", &n))
{
memset(isFree, false, sizeof(false));
for (int i = 1; i <= n; i++)
scanf("%d%d", &maps[i].x, &maps[i].y);
scanf("%d", &m);
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
isFree[u][v] = isFree[v][u] = true;
}
prim();
}
return 0;
}
模板题
//poj1258
#include
#include
#include
using namespace std;
const int N = 105, INF = 0x3f3f3f3f;
int maps[N][N],visit[N];
int d[N];
int n;
int prim()
{
int ans = 0;
for (int i = 2; i <= n; i++)
d[i] = maps[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[j] < d[t] || t == -1)
t = j;
}
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j])
d[j] = min(d[j], maps[t][j]);
}
return ans;
}
int main()
{
while (~scanf("%d", &n))
{
memset(maps, 0x3f, sizeof(maps));
memset(visit, 0, sizeof(visit));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
int w;
scanf("%d", &w);
if (w == 0)continue;
maps[i][j] = w;
maps[j][i] = w;
}
printf("%d\n", prim());
}
return 0;
}
BFS + Prime
暴力对每个A或者S的点进行bfs求到其它点的距离建图,然后套用最小生成树模板
//poj 3026
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 505; //数组开大一点,pojdiscuss说太小会WA
//bfs用的
int visit[N][N];
int cost[N][N];
char str[N][N]; //str构造bfs的图maps
int maps[N][N];
int step[4][2] = { {1,0},{-1,0},{0,-1},{0,1} };
typedef pair<int, int> pp;
vector<pp> point;
//prime用的
int visit_for_prime[N];
int map_for_prime[N][N];
int d[N];
int n, m;
void bfs()
{
int cnt = 0;
//求容器中每两点之间的距离,建prime的图,编号1-vector的size
for (vector<pp>::iterator it = point.begin(); it != point.end(); it++)
{
cnt++;
//下方是从一个点开始的bfs
memset(visit, 0, sizeof(visit));
memset(cost, 0, sizeof(cost));
queue<pp> Q;
Q.push(pp(it->first, it->second));
visit[it->first][it->second] = 1;
while (Q.size())
{
pp t = Q.front();
Q.pop();
visit[t.first][t.second] = 1;
for (int i = 0; i < 4; i++)
{
int x = t.first + step[i][0];
int y = t.second + step[i][1];
if (x > 0 && x <= n && y > 0 && y <= m && !visit[x][y] && maps[x][y] != 1) {
cost[x][y] = cost[t.first][t.second] + 1;
visit[x][y] = 1;
Q.push(pp(x, y));
}
}
}
int cnt2 = 0;
//下方是记录该点(bfs源点)到其它点的距离,建图
for (vector<pp>::iterator it2 = point.begin(); it2 != point.end(); it2++)
{
cnt2++;
if (it == it2)continue;
map_for_prime[cnt][cnt2] = map_for_prime[cnt2][cnt] = cost[it2->first][it2->second];
}
}
}
int prim()
{
int ans = 0;
int n = point.size();
memset(visit_for_prime, 0, sizeof(visit_for_prime));
for (int i = 2; i <= n; i++)
d[i] = map_for_prime[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit_for_prime[j])
if (d[t] > d[j] || t == -1)
t = j;
}
if (t == -1)break;
visit_for_prime[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit_for_prime[j]) {
d[j] = min(map_for_prime[t][j], d[j]);
}
}
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
memset(maps, 0, sizeof(maps));
point.clear();
scanf("%d%d", &m, &n);
gets(str[0]);
for (int i = 1; i <= n; i++)
{
gets(str[i]);
for (int j = 0; j < m; j++) {
if (str[i][j] == '#')maps[i][j + 1] = 1;
else maps[i][j + 1] = 0;
if (str[i][j] == 'A' || str[i][j] == 'S') {
point.push_back(pp(i, j + 1)); //把每个点存起来
}
}
}
bfs();
printf("%d\n", prim());
}
return 0;
}
模板题
//hdu 1233
#include
#include
#include
using namespace std;
const int N = 105, INF = 0x3f3f3f3f;
int maps[N][N],visit[N];
int d[N];
int n;
int prim()
{
int ans = 0;
for (int i = 2; i <= n; i++)
d[i] = maps[1][i];
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j])
if (d[j] < d[t] || t == -1)
t = j;
}
visit[t] = 1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j])
d[j] = min(d[j], maps[t][j]);
}
return ans;
}
int main()
{
while (~scanf("%d", &n),n)
{
memset(maps, 0x3f, sizeof(maps));
memset(visit, 0, sizeof(visit));
for (int i = 1; i <= n*(n-1)/2; i++)
{
int u,v,w;
scanf("%d%d%d", &u,&v,&w);
maps[u][v] = w;
maps[v][u] = w;
}
printf("%d\n", prim());
}
return 0;
}
套用prim求最小生成树,注意距离不在(10,1000)的不建边。
感觉这题浮点数比大小巨坑,10.000000 <= len && len <= 1000.000001,少一个0都wa,去了杭电oj的discussion发现的
用相减大于>=eps(1e-6)也过不了,搞不懂。
//hdu 1875
#include
#include
#include
#include
using namespace std;
const int N = 105;
const double INF = 1e15;
const double eps = 1e-5;
int visit[N];
double d[N];
int n,m;
struct node {
int x, y;
}maps[N];
double getDis(double x1, double y1, double x2, double y2)
{
return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
double prim()
{
memset(visit, 0, sizeof(visit));
for (int i = 1; i <= n; i++)
d[i] = INF;
double ans = 0;
for (int i = 2; i <= n; i++) {
double len = getDis(maps[1].x, maps[1].y, maps[i].x, maps[i].y);
if (10.000000 <= len && len <= 1000.000001) //距离不在(10,1000)的不建边
d[i] = len;
}
d[1] = 0;
for (int i = 2; i <= n; i++)
{
int t = -1;
for (int j = 2; j <= n; j++)
{
if (!visit[j] && d[j]!=INF)
if (d[t] > d[j]|| t == -1)
t = j;
}
visit[t] = 1;
if (!(10.000000 <= d[t] && d[t] <= 1000.000001))return -1;
ans += d[t];
for (int j = 2; j <= n; j++)
if (!visit[j]) {
double len = getDis(maps[t].x, maps[t].y, maps[j].x, maps[j].y);
if(10.000000 <= len && len <= 1000.000001)
d[j] = min(d[j], len);
}
}
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &maps[i].x,&maps[i].y);
int flag = 0;
double ans = prim();
if (ans==-1)printf("oh!\n");
else printf("%.1lf\n", ans*100);
}
return 0;
}