目录
- A - Jungle Roads (POJ - 1251)
- B - Networking (POJ - 1287)
- C - Building a Space Station (POJ - 2031)
- D - Constructing Roads (POJ - 2421)
- E - Truck History (POJ - 1789)
- F - Arctic Network (POJ - 2349)
- G - Highways (POJ - 1751)
- H - Agri-Net (POJ - 1258)
- I - Borg Maze (POJ - 3026)
- J - The Unique MST (POJ - 1679)
- K - 还是畅通工程 (HDU - 1233)
- L - 畅通工程再续 (HDU - 1875)
A - Jungle Roads (POJ - 1251)
思路: 把字母转化为数字,然后再跑一遍最小生成树。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 30;
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
int n, m, ans, f[maxn];
char ch1, ch2;
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0, result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
num++;
f[f1] = f2;
result += E[i].w;
}
if(num == n - 1)
break;
}
printf("%d\n", result);
}
int main() {
while(~scanf("%d", &n)) {
if(n == 0)
break;
m = 0;
for(int i = 1, w; i < n; i++) {
scanf(" %c %d", &ch1, &ans);
for(int j = 1; j <= ans; j++) {
scanf(" %c %d", &ch2, &w);
E[++m].u = ch1 - 'A' + 1;
E[m].v = ch2 - 'A' + 1;
E[m].w = w;
}
}
Kruskal(n, m);
}
system("pause");
return 0;
}
B - Networking (POJ - 1287)
思路: 最小生成树模板题
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 110;
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
int n, m, f[maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
result += E[i].w;
num++;
}
if(num == n - 1)
break;
}
printf("%d\n", result);
}
int main() {
while(~scanf("%d", &n)) {
if(n == 0)
break;
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
}
Kruskal(n, m);
}
system("pause");
return 0;
}
C - Building a Space Station (POJ - 2031)
思路: 求出每个球心直接的距离,如果两球心间的距离小于两球的半径和,那么就令这条边的长度为0,否则为两球心间的距离减去两球半径和。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 110;
struct Edge{
int u, v;
double w;
bool operator < (const Edge &r) const{
return w < r.w;
}
}E[maxn * maxn];
int n, m, t, f[maxn];
struct Point{
double x, y, z, r;
}P[maxn];
double Dist(Point a, Point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z));
};
int find(int x) {
return x == f[x]?x:f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
double result = 0;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
result += E[i].w;
num++;
f[f1] = f2;
}
if(num == n - 1)
break;
}
printf("%.3f\n", result);
}
int main() {
while(~scanf("%d", &n)) {
if(n == 0)
break;
for(int i = 1; i <= n; i++) {
scanf("%lf %lf %lf %lf", &P[i].x, &P[i].y, &P[i].z, &P[i].r);
}
int ans = 0;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
E[++ans].u = i;
E[ans].v = j;
if(Dist(P[i], P[j]) < P[i].r + P[j].r)
E[ans].w = 0;
else
E[ans].w = Dist(P[i], P[j]) - P[i].r - P[j].r;
}
}
Kruskal(n, ans);
}
system("pause");
return 0;
}
D - Constructing Roads (POJ - 2421)
思路: 建边和之前有一点不一样,MST模板题
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 110;
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
int n, m, f[maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
result += E[i].w;
num++;
}
if(num == n - 1)
break;
}
printf("%d\n", result);
}
int main() {
scanf("%d", &n);
int ans = 0;
for(int i = 1, x; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d", &x);
if(i > j) {
E[++ans].u = i;
E[ans].v = j;
E[ans].w = x;
}
}
}
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
scanf("%d %d", &E[++ans].u, &E[ans].v);
E[ans].w = 0;
}
Kruskal(n, ans);
system("pause");
return 0;
}
E - Truck History (POJ - 1789)
题意: n个卡车类型,刚开始只有一个类型,其他类型都是由一个类型直接或间接产生,一个类型到另一个类型的花费是它们之间的字符不同的个数,问产生所有类型卡车的最小花费。
思路: 看懂了题意这题就很简单了,就是一道MST的水题。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 2e3 + 10;
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
string st[maxn];
int n, m, f[maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
result += E[i].w;
num++;
}
if(num == n - 1)
break;
}
cout<<"The highest possible quality is 1/"<<result<<".\n";
}
int main() {
while(cin>>n) {
if(n == 0)
break;
for(int i = 1; i <= n; i++)
cin>>st[i];
int ans = 0;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
int k = 0;
for(int p = 0; p < 7; p++) {
if(st[i][p] != st[j][p])
k++;
}
E[++ans].u = i;
E[ans].v = j;
E[ans]. w = k;
}
}
Kruskal(n, ans);
}
system("pause");
return 0;
}
F - Arctic Network (POJ - 2349)
题意: 有s颗卫星和p个哨所,有卫星的两个哨所之间可以任意通信;否则,一个哨所只能和距离它小于等于D的哨所通信。给出卫星的数量和p个哨所的坐标,求D的最小值。
思路: s颗卫星则说明有 s − 1 s - 1 s−1条边直接相连,贪心地去想,肯定要让有卫星的哨所直接距离最长,所以只用构造一个 n − 1 − ( s − 1 ) n - 1 - (s - 1) n−1−(s−1)条边的MST了。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 5e2 + 10;
struct Edge{
int u, v;
double w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
string st[maxn];
int n, m, f[maxn], t, s, p;
struct Point{
double x, y;
}P[maxn];
double Dist(Point a, Point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
double result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
result = E[i].w;
num++;
}
if(num == n - 1 - (s - 1))
break;
}
printf("%.2f\n", result);
}
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d %d", &s, &p);
for(int i = 1; i <= p; i++) {
scanf("%lf %lf", &P[i].x, &P[i].y);
}
int ans = 0;
for(int i = 1; i < p; i++) {
for(int j = i + 1; j <= p; j++) {
E[++ans].u = i;
E[ans].v = j;
E[ans].w = Dist(P[i], P[j]);
}
}
Kruskal(p, ans);
}
system("pause");
return 0;
}
G - Highways (POJ - 1751)
思路: MST裸题,加个路径输出就好了。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 1e3 + 10;
struct Edge {
int u, v;
double w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
struct Point{
double x, y;
}P[maxn];
int n, m, pa[maxn], pb[maxn], f[maxn];
double Dist(Point a, Point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
int cnt = 0;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
num++;
if(E[i].w != 0) {
pa[++cnt] = E[i].u;
pb[cnt] = E[i].v;
}
}
if(num == n - 1)
break;
}
for(int i = 1; i <= cnt; i++) {
printf("%d %d\n", pa[i], pb[i]);
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lf %lf", &P[i].x, &P[i].y);
}
int ans = 0;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
E[++ans].u = i;
E[ans].v = j;
E[ans].w = Dist(P[i], P[j]);
}
}
scanf("%d", &m);
for(int i = 1, st, ed; i <= m; i++) {
scanf("%d %d", &st, &ed);
E[++ans].u = st;
E[ans].v = ed;
E[ans].w = 0;
}
Kruskal(n, ans);
// system("pause");
return 0;
}
H - Agri-Net (POJ - 1258)
思路: MST裸题
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 5e2 + 10;
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
string st[maxn];
int n, m, f[maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
for(int i = 1; i <= n; i++)
f[i] = i;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
f[f1] = f2;
result += E[i].w;
num++;
}
if(num == n - 1)
break;
}
printf("%d\n", result);
}
int main() {
while(~scanf("%d", &n)) {
m = 0;
for(int i = 1, x; i <= n; i++) {
for(int j = 1; j <= n; j++) {
scanf("%d", &x);
if(j > i) {
E[++m].u = i;
E[m].v = j;
E[m].w = x;
}
}
}
Kruskal(n, m);
}
system("pause");
return 0;
}
I - Borg Maze (POJ - 3026)
题意: 问从S出发,派机器人到A的地方,机器人可以在图中分裂,求最少步数。
思路: 因为机器人可以分裂,那到一个A的最近的距离就是离它最近的A或S。我们可以用BFS搜索任意两个A或S间的距离,然后再求一个最小生成树就是答案了。我认为是道挺好的题目,就是后台的数据有点问题,n和m后面会有空格,需要处理一下。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 60;
char mp[maxn][maxn];
int t, n, m, id[maxn][maxn], vis[maxn][maxn], ans, f[maxn];
int moven[5][5] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn * maxn * maxn];
struct Node{
int x, y, id, d;
};
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
bool check(int x, int y) {
if(x < 1 || x > n || y < 1 || y > n || id[x][y] == -1 || vis[x][y]) return false;
return true;
}
void BFS(int x, int y) {
vis[x][y] = 1;
queue<Node>q;
Node tmp;
tmp.x = x, tmp.y = y, tmp.id = id[x][y], tmp.d = 0;
q.push(tmp);
int id1 = id[x][y];
while(!q.empty()) {
Node now = q.front();
q.pop();
for(int i = 0; i < 4; i++) {
int mx = now.x + moven[i][0];
int my = now.y + moven[i][1];
if(check(mx, my)) {
vis[mx][my] = 1;
tmp.x = mx, tmp.y = my, tmp.id = id[mx][my], tmp.d = now.d + 1;
q.push(tmp);
if(tmp.id != 0) {
E[++ans].u = id1;
E[ans].v = tmp.id;
E[ans].w = tmp.d;
}
}
}
}
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
num++;
result += E[i].w;
f[f1] = f2;
}
if(num == n - 1)
break;
}
printf("%d\n", result);
}
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d %d\n", &m, &n);
for(int i = 1; i <= n; i++) {
gets(mp[i] + 1);
}
memset(id, 0, sizeof(id));
ans = 0;
int num = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(mp[i][j] == 'A' || mp[i][j] == 'S') {
id[i][j] = ++num;
}
if(mp[i][j] == '#')
id[i][j] = -1;
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(mp[i][j] == 'A' || mp[i][j] == 'S'){
memset(vis, 0, sizeof(vis));
BFS(i, j);
}
}
}
Kruskal(num, ans);
}
system("pause");
return 0;
}
J - The Unique MST (POJ - 1679)
题意: 问最小生成树是不是唯一的,如果是则输出边权和,如果不是输出Not Unique!。
思路: 首先生成一个最小生成树,然后每次删掉其中的一条边,再去生成最小生成树,如果能生成权值和与之前一样的,那说明最小生成树不唯一,否则唯一。
AC Code:
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
const int maxn = 110;
int t, n, m, ans, f[maxn], path[maxn];
struct Edge{
int u, v, w;
bool operator < (const Edge &r) const {
return w < r.w;
}
}E[maxn * maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
void init() {
for(int i = 1; i <= n; i++)
f[i] = i;
}
void Kruskal(int n, int m) {
int num = 0;
int result = 0;
sort(E + 1, E + 1 + m);
init();
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2) {
path[++num] = i;
result += E[i].w;
f[f1] = f2;
}
if(num == n - 1)
break;
}
int flag = 0;
for(int i = 1; i <= num; i++) {
int sum = 0;
int ans = 0;
init();
for(int j = 1; j <= m; j++) {
if(j == path[i])
continue;
int f1 = find(E[j].u);
int f2 = find(E[j].v);
if(f1 != f2) {
ans++;
sum += E[j].w;
f[f1] = f2;
}
if(ans == n - 1)
break;
}
if(ans == n - 1 && sum == result){
flag = 1;
break;
}
}
if(flag)
printf("Not Unique!\n");
else
printf("%d\n", result);
}
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d %d %d", &E[i].u, &E[i].v, &E[i].w);
}
Kruskal(n, m);
}
system("pause");
return 0;
}
K - 还是畅通工程 (HDU - 1233)
思路: MST裸题
AC Code:
#include<cstdio>
#include<vector>
#include<string>
#include<algorithm>
#include<iostream>
#include<cstring>
#define N 10005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,f[N];
struct edge{
int u,v,w;
}e[N];
bool cmp(edge a,edge b){
return a.w<b.w;
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
int K(int n,int m){
int c=n,ans=0;
for(int i=1;i<=n;i++){
f[i]=i;
}
sort(e,e+m,cmp);
for(int i=0;i<m;i++){
int f1=find(e[i].u);
int f2=find(e[i].v);
if(f1!=f2){
ans=ans+e[i].w;
c--;
f[f1]=f2;
}
if(c==1) break;
}
if(c>1) return -1;
else return ans;
}
int main(void){
while(scanf("%d",&n)!=EOF){
if(n==0) break;
m=n*(n-1)/2;
for(int i=0;i<m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
printf("%d\n",K(n,m));
}
}
L - 畅通工程再续 (HDU - 1875)
思路: MST裸题,多了个边权的约束。
AC Code:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
struct Edge{
int u, v;
double w;
bool operator < (const Edge &r) const{
return w < r.w;
}
}E[maxn * maxn];
int n, m, t, f[maxn];
struct Point{
double x, y;
}P[maxn];
double Dist(Point a, Point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
};
int find(int x) {
return x == f[x]?x:f[x] = find(f[x]);
}
void Kruskal(int n, int m) {
int num = 0;
double result = 0;
sort(E + 1, E + 1 + m);
for(int i = 1; i <= n; i++)
f[i] = i;
for(int i = 1; i <= m; i++) {
int f1 = find(E[i].u);
int f2 = find(E[i].v);
if(f1 != f2 && E[i].w >= 10 && E[i].w <= 1000) {
result += E[i].w;
num++;
f[f1] = f2;
}
if(num == n - 1)
break;
}
if(num == n - 1)
printf("%.1f\n", result * 100);
else
puts("oh!");
}
int main() {
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lf %lf", &P[i].x, &P[i].y);
}
int ans = 0;
for(int i = 1; i < n; i++) {
for(int j = i + 1; j <= n; j++) {
E[++ans].u = i;
E[ans].v = j;
E[ans].w = Dist(P[i], P[j]);
}
}
Kruskal(n, ans);
}
system("pause");
return 0;
}