隨便說點:
博主正在刷kuangbin專題的題目,初學者,沒接觸過什麼算法,刷題的初衷是備戰藍橋杯,後來發現了算法資料大多是針對acm的,挑選kuangbin專題入門也是如此,畢竟這樣分類看起來比較有目的的刷題。
所以有的代碼比較冗餘,越往後面的題解代碼變化越大,
代碼的風格和算法思想也是在一步步的學習和進步,多多包容,互相借鑑。
建議做題順序:
做最小生成樹專題沒最短路和並查集專題時那麼吃力,題目難度有下降。所以把題解都整合在一篇博客裏
最小生成樹基礎:1 2 4 5 6 9 12 14
最小生成樹應用:10 3 8 7
這是我做完一遍之後覺得比較好的做題順序,由易到難,相同類型題放在一起加深理解。
題解目錄
- 1.POJ 1251 Jungle Roads
- 2.POJ 1287 Networking
- 3.POJ 2031 Building a Space Station
- 4.POJ 2421 Constructing Roads
- 5.ZOJ 1586 QS Network
- 6.POJ 1789 Truck History
- 7.POJ 2349 Arctic Network
- 8.POJ 1751 Highways
- 9.POJ 1258 Agri-Net
- 10.POJ 3026 Borg Maze
- 11.POJ 1679 The Unique MST(次小生成樹,放生成樹專題寫)
- 12.HDU 1233 還是暢通工程
- 13.HDU 1301 Jungle Roads(與題目1重複)
- 14.HDU 1875 暢通工程再續
1.POJ 1251 Jungle Roads
把字符轉化成整型,然後套用模板
//poj1251
#include<cstdio>
#include<cstring>
#include<algorithm>
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;
}
2.POJ 1287 Networking
模板題
#include<cstdio>
#include<cstring>
#include<algorithm>
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;
}
3.POJ 2031 Building a Space Station
prim,注意 若兩圓心距離-半徑之和< =0則兩點權值設置爲0
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
4.POJ 2421 Constructing Roads
模板題
//poj2421
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
5.ZOJ 1586 QS Network
模板題,邊的權值=各自的適配器+道路的花費
//zoj 1586
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
6.POJ 1789 Truck History
處理一下圖,邊的權值爲兩個字符串對應位置字母不同的個數
然後套用模板即可。
//poj1789
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
7.POJ 2349 Arctic Network
因爲n個衛星可以同時使得n-1條邊免費,故還是kustral
把邊排序,最小生成樹,記錄每次加入的邊值,最後輸出倒數第m條邊即可,m = 免費的邊數+1。
即不算後面n-1條免費的邊
//poj2349
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
8.POJ 1751 Highways
prim,注意已經存在的邊權值設置爲0,還有就是輸出邊時涉及邊的兩點,可以把d[]數組定義成結構體數組,更新邊的權值時順便記錄下是被哪個點更新的。
//poj1751
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}
9.POJ 1258 Agri-Net
模板題
//poj1258
#include<cstdio>
#include<cstring>
#include<algorithm>
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;
}
10.POJ 3026 Borg Maze
BFS + Prime
暴力對每個A或者S的點進行bfs求到其它點的距離建圖,然後套用最小生成樹模板
//poj 3026
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
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;
}
11.POJ 1679 The Unique MST(次小生成樹,放生成樹專題寫)
12.HDU 1233 還是暢通工程
模板題
//hdu 1233
#include<cstdio>
#include<cstring>
#include<algorithm>
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;
}
13.HDU 1301 Jungle Roads(與題目1重複)
14.HDU 1875 暢通工程再續
套用prim求最小生成樹,注意距離不在(10,1000)的不建邊。
感覺這題浮點數比大小巨坑,10.000000 <= len && len <= 1000.000001,少一個0都wa,去了杭電oj的discussion發現的
用相減大於>=eps(1e-6)也過不了,搞不懂。
//hdu 1875
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
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;
}