目录
- 1. poj 1251 Jungle Roads
- 2. poj 1287 Networking
- 3. poj 2301 Building a Space Station
- 4. poj 2421 Constructing Roads
- 5. zoj 1610 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
1. poj 1251 Jungle Roads
#include
#include
using namespace std;
const int MAXN = 200;
int set[MAXN];
struct Edge{
int x,y,z;
}edge[MAXN];
int Find_set(int x){
if(x != set[x]) set[x] = Find_set(set[x]);
return set[x];
}
void Kruskal(int num,int m){
int ans = 0;
int tot = 0;
for(int i=0;i<num;i++){
set[i] = i;
}
for(int i=0;i<m;i++){
int x = Find_set(edge[i].x);
int y = Find_set(edge[i].y);
if(x == y) continue;
set[x] = set[y];
tot++;
ans += edge[i].z;
if(tot == num-1) break;
}
cout<<ans<<endl;
}
bool cmp(Edge x,Edge y){
return x.z<y.z;
}
int main(){
int n,m;
char c,cc;
while(cin>>n&&n){
int num = 0;
for(int i=1;i<n;i++){
cin>>c>>m;
for(int j=0;j<m;j++){
edge[num].x = c-'A';
cin>>cc;
edge[num].y = cc-'A';
cin>>edge[num].z;
num++;
}
}
sort(edge,edge+num,cmp);
Kruskal(n,num);
}
return 0;
}
2. poj 1287 Networking
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int s[MAXN];
struct Edge{
int u, v, w;
bool operator < (const Edge &B)const{
return w < B.w;
}
}edge[MAXN];
int FIND(int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
}
int Kruskal(int n, int m){
int ans = 0;
int num = 0;
for(int i=0;i<m;i++){
int u = edge[i].u;
int v = edge[i].v;
u = FIND(u);
v = FIND(v);
if(u == v) continue;
s[u] = v;
num += 1;
ans += edge[i].w;
if(num == n - 1) break;
}
return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
while(cin >> n){
if(n == 0) break;
for(int i=1;i<=n;i++) s[i] = i;
cin >> m;
for(int i=0;i<m;i++){
cin >> edge[i].u >> edge[i].v >> edge[i].w;
}sort(edge, edge + m);
cout << Kruskal(n, m) << '\n';
}
return 0;
}
3. poj 2301 Building a Space Station
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 300;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
struct Point{
double x, y, z;
double r;
}pt[MAXN];
int dcmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Line{
int x, y;
double dis;
bool operator < (const Line &B)const{
return dcmp(dis - B.dis) < 0;
}
}le[30000];
int s[MAXN];
int FIND(int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
}
double kruskal(int n, int m){
double ans = 0;
int num = 0;
for(int i=0;i<m;i++){
int x = FIND(le[i].x);
int y = FIND(le[i].y);
if(x == y) continue;
num += 1;
s[x] = y;
ans += le[i].dis;
if(num == n - 1) break;
}
return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
while(cin >> n && n){
for(int i=1;i<=n;i++) s[i] = i;
for(int i=1;i<=n;i++){
cin >> pt[i].x >> pt[i].y >> pt[i].z >> pt[i].r;
}
int m = 0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
le[m].dis = sqrt(pow(pt[i].x - pt[j].x, 2) + pow(pt[i].y - pt[j].y, 2) + pow(pt[i].z - pt[j].z, 2));
le[m].dis = max(0.0, le[m].dis - pt[i].r - pt[j].r);
le[m].x = i;
le[m].y = j;
m += 1;
}
}sort(le, le + m);
for(int i=0;i<m;i++){
}
cout << fixed << setprecision(3) << kruskal(n, m) << '\n';
}
return 0;
}
4. poj 2421 Constructing Roads
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 111;
const int INF = 0x3f3f3f3f;
struct st{
int x, y;
int dis;
bool operator <(const st &B)const{
return dis < B.dis;
}
}pt[MAXN * MAXN];
int s[MAXN];
int FIND(int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
}
int num = 0;
int kruskal(int n, int m){
int ans = 0;
if(num >= n - 1) return 0;
for(int i=0;i<m;i++){
int x = FIND(pt[i].x);
int y = FIND(pt[i].y);
if(x == y) continue;
s[x] = y;
ans += pt[i].dis;
num += 1;
if(num == n - 1) break;
}
return ans;
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
int q;
cin >> n;
for(int i=1;i<=n;i++) s[i] = i;
int m = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin >> pt[m].dis;
if(i == j) continue;
pt[m].x = i;
pt[m].y = j;
m += 1;
}
}sort(pt, pt + m);
cin >> q;
while(q--){
int u, v;
cin >> u >> v;
u = FIND(u);
v = FIND(v);
if(u == v) continue;
num += 1;
s[u] = v;
}
cout << kruskal(n, m);
return 0;
}
5. zoj 1610 QS Network
#include
using namespace std;
struct st{
int x, y;
int dis;
};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<int> s(n);
for(int i=0;i<n;i++) s[i] = i;
vector<int> a(n);
for(int i=0;i<n;i++) cin >> a[i];
function<int(int)> FIND = [&](int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
};
vector<st> vs;
function<int()> kruskal = [&](){
int num = 0;
int ans = 0;
for(int i=0;i<vs.size();i++){
int x = FIND(vs[i].x);
int y = FIND(vs[i].y);
if(x == y) continue;
s[x] = y;
ans += vs[i].dis;
if(num == n - 1) break;
}
return ans;
};
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int x;
cin >> x;
if(i <= j) continue;
vs.push_back(st{i, j, x + a[i] + a[j]});
}
}
sort(vs.begin(), vs.end(), [&](st x, st y){
return x.dis < y.dis;
});
cout << kruskal() << '\n';
}
return 0;
}
6. poj 1789 Truck History
- 题意仔细理解一下,将每个字符串看作一个点,实际上是求这个图的最小生成树的权值和
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 2e3 + 10;
struct st{
int u, v, w;
bool operator < (const st &B)const{
return w < B.w;
}
}s[N * N];
string Data[N];
int tot = 0;
int a = 0;
int b = 0;
int st[N];
int FIND(int x){
return x == st[x] ? x : st[x] = FIND(st[x]);
}
void Kruskal(int n, int m){
int num = 0;
for(int i=0;i<m;i++){
int u = FIND(s[i].u);
int v = FIND(s[i].v);
int w = s[i].w;
if(u == v) continue;
st[u] = v;
a += w;
num += 1;
if(num == n - 1) break;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
while(cin >> n && n){
for(int i=0;i<n;i++){
cin >> Data[i];
st[i] = i;
}
tot = a = b = 0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
int sz = (int)Data[i].size();
int w = 0;
for(int k=0;k<sz;k++){
if(Data[i][k] != Data[j][k]) w += 1;
}
s[tot].u = i;
s[tot].v = j;
s[tot].w = w;
b += w;
tot += 1;
}
}sort(s, s + tot);
Kruskal(n, tot);
cout << "The highest possible quality is " << 1 << '/' << a << ".\n";
}
return 0;
}
7. poj 2349 Arctic Network
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 600;
typedef double DB;
const DB eps = 1e-8;
int cmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct st{
int x, y;
double z;
bool operator < (const st &B)const{
return cmp(z - B.z) < 0;
}
}Data[N * N];
int ss[N];
int FIND(int x){
return ss[x] == x ? x :ss[x] = FIND(ss[x]);
}
vector<double> vec;
void Kruskal(int n, int m){
int num = 0;
for(int i=0;i<m;i++){
int u = Data[i].x;
int v = Data[i].y;
double w = Data[i].z;
u = FIND(u);
v = FIND(v);
if(u == v) continue;
ss[u] = v;
num += 1;
vec.push_back(w);
if(num == n - 1) break;
}
}
pair<double, double> vs[N];
int main(){
int tt;
cin >> tt;
while(tt--){
int s, p;
cin >> s >> p;
for(int i=1;i<=p;i++) ss[i] = i;
int m = 0;
for(int i=1;i<=p;i++){
cin >> vs[i].first >> vs[i].second;
}
for(int i=1;i<=p;i++){
for(int j=i+1;j<=p;j++){
Data[m].x = i;
Data[m].y = j;
Data[m].z = hypot(vs[i].first - vs[j].first, vs[i].second - vs[j].second);
m += 1;
}
}sort(Data, Data + m);
vec.clear();
Kruskal(p, m);
reverse(vec.begin(), vec.end());
cout << fixed << setprecision(2) << *(vec.begin() + s - 1) << '\n';
}
return 0;
}
8. poj 1751 Highways
- 给你图中几条路径,补充完整最小生成树,已经构成路径的点放到一个集合里面即可,然后正常求
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 760;
int x[N], y[N];
struct st{
int u, v;
ll w;
bool operator < (const st &B)const{
return w < B.w;
}
}s[N * N];
int st[N];
int FIND(int x){
return x == st[x] ? x : st[x] = FIND(st[x]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
int tot = 0;
for(int i=0;i<n;i++){
cin >> x[i] >> y[i];
st[i] = i;
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
s[tot].u = i;
s[tot].v = j;
s[tot].w = 1ll * (x[j] - x[i]) * (x[j] - x[i]) + 1ll * (y[j] - y[i]) * (y[j] - y[i]);
tot += 1;
}
}sort(s, s + tot);
int m;
cin >> m;
for(int i=0;i<m;i++){
int u, v;
cin >> u >> v;
u -= 1;
v -= 1;
u = FIND(u);
v = FIND(v);
if(u != v) st[u] = v;
}
vector<pair<int, int> > vs;
for(int i=0;i<tot;i++){
int u = FIND(s[i].u);
int v = FIND(s[i].v);
int w = s[i].w;
if(u == v) continue;
st[u] = v;
vs.push_back(make_pair(s[i].u + 1, s[i].v + 1));
}
for(int i=0;i<(int)vs.size();i++){
cout << vs[i].first << ' ' << vs[i].second << '\n';
}
return 0;
}
9. poj 1258 Agri-Net
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 200;
struct st{
int u, v;
int w;
bool operator < (const st &B)const{
return w < B.w;
}
}s[N * N];
int st[N];
int FIND(int x){
return x == st[x] ? x : st[x] = FIND(st[x]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
while(cin >> n){
int tot = 0;
for(int i=0;i<n;i++){
st[i] = i;
for(int j=0;j<n;j++){
int x;
cin >> x;
if(i >= j) continue;
s[tot].u = i;
s[tot].v = j;
s[tot].w = x;
tot += 1;
}
}
sort(s, s + tot);
int ans = 0;
for(int i=0;i<tot;i++){
int u = FIND(s[i].u);
int v = FIND(s[i].v);
int w = s[i].w;
if(u == v) continue;
st[u] = v;
ans += w;
}
cout << ans << '\n';
}
return 0;
}
10. poj 3026 Borg Maze
- 这个题是个好题,说你在位置 S S S,现在要去每一个 A A A点,然后你走的过程中可以分裂,换句话说就是你不用走回头路,然后问你最少需要多长时间完成这个任务
- 真好久都没有遇到过这样的读入了,我不理解为什么 g e t c h a r ( ) getchar() getchar()读回车不对,涨姿势了,可以用sacnf("%d%d\n")读这个回车,然后这样读就能过,但是我用scanf("%d%d);getchar();就不行,也许是他输入没那么规范?
- 说说这个题的思路,因为你走路的过程中可以分裂,所以容易想到可以转化为最小生成树问题,也就是把每两个点的最短距离都求出来,然后建一棵MST就好了,边权和即为答案
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 105;
char mp[N][N];
int Data[N][N];
bool vis[N][N];
int n, m;
int now;
struct st{
int x, y, d;
st(){}
st(int x, int y, int d): x(x), y(y), d(d){}
};
int xx[] = {1, 0, -1, 0};
int yy[] = {0, 1, 0, -1};
struct Some{
int u, v, w;
bool operator < (const Some &B)const{
return w < B.w;
}
}some[205 * 105];
int s[105];
int FIND(int x){
return x == s[x] ? x : s[x] = FIND(s[x]);
}
int main(){
int t;
scanf("%d", &t);
while(t--){
scanf("%d%d\n", &m, &n);
memset(Data, 0, sizeof Data);
now = 1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%c", &mp[i][j]);
if(mp[i][j] == 'A' || mp[i][j] == 'S'){
Data[i][j] = now;
now += 1;
}
}getchar();
}
for(int i=1;i<=now;i++){
s[i] = i;
}
int kk = 0;
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);
st s = st(i, j, 0);
queue<st> q;
q.push(s);
while(!q.empty()){
s = q.front();
q.pop();
vis[s.x][s.y] = true;
for(int k=0;k<4;k++){
int dx = s.x + xx[k];
int dy = s.y + yy[k];
if(dx < 1 || dy < 1 || dx > n || dy > m || mp[dx][dy] == '#' || vis[dx][dy]) continue;
if(mp[dx][dy] == 'A' || mp[dx][dy] == 'S'){
some[kk].u = Data[dx][dy];
some[kk].v = Data[i][j];
some[kk].w = s.d + 1;
kk += 1;
}
vis[dx][dy] = true;
q.push(st(dx, dy, s.d + 1));
}
}
}
}
}sort(some, some + kk);
int ans = 0;
for(int i=0;i<kk;i++){
int u = FIND(some[i].u);
int v = FIND(some[i].v);
int w = some[i].w;
if(u == v) continue;
s[u] = v;
ans += w;
}
printf("%d\n", ans);
}
return 0;
}
11. poj 1679 The Unique MST
- 问最小生成树是否唯一
- 暴力方法显然,也可以通过,就是求出最小生成树以后逐一禁用每一条边,然后再求,每次求完之后看得到的最小生成树的边权和是不是唯一的,容易写出下面的程序
#include
#include
#include
#include
#include
using namespace std;
const int N = 200;
int st[N], s_u[N], s_v[N];
int FIND(int x){
return x == st[x] ? x : st[x] = FIND(st[x]);
}
struct st{
int u, v, w;
bool operator < (const st &B)const{
return w < B.w;
}
}s[N * N];
int main(){
int t;
cin >> t;
while(t--){
int n, m;
cin >> n >> m;
for(int i=1;i<=n;i++) st[i] = i;
for(int i=0;i<m;i++){
cin >> s[i].u >> s[i].v >> s[i].w;
}sort(s, s + m);
int ans = 0;
bool ok = true;
int now = 0;
for(int i=0;i<m;i++){
int u = FIND(s[i].u);
int v = FIND(s[i].v);
int w = s[i].w;
if(u == v) continue;
s_u[now] = s[i].u;
s_v[now] = s[i].v;
now += 1;
st[u] = v;
ans += w;
}
for(int i=0;i<now;i++){
for(int j=1;j<=n;j++) st[j] = j;
int res = 0;
int k = 0;
for(int j=0;j<m;j++){
int u = FIND(s[j].u);
int v = FIND(s[j].v);
int w = s[j].w;
if(u == v || (s_u[i] == s[j].u && s_v[i] == s[j].v)) continue;
res += w;
st[u] = v;
k += 1;
}
if(res == ans && k == n - 1) ok = false;
}
if(ok) cout << ans << '\n';
else{
cout << "Not Unique!" << '\n';
}
}
return 0;
}
- 如果按照常规想法,就是求这棵树的次小生成树,如果发现它也是最小生成树,那么就说明MST不唯一,基本想法就是把除了MST以外的最短边加入到MST中,这样一定出现了一个环,比如说我们加入的是 u − > v u->v u−>v这条边,设权值为 w w w,如果发现 u − > l c a u->lca u−>lca或者 v − > l c a v->lca v−>lca这二者之间存在一条边边权等于 w w w,那么说明次小生成树不唯一