[kuangbin带你飞]专题六 最小生成树 解题报告

文章目录

    • A - Jungle Roads
    • B - Networking
    • C - Building a Space Station(待补)
    • D - Constructing Roads
    • E - QS Network
    • F - Truck History(待补)
    • G - Arctic Network
    • H - Highways
    • I - Agri-Net
    • J - Borg Maze(待补)
    • K - The Unique MST

A - Jungle Roads

POJ - 1251

题意&&解法:裸题

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MXN = 1e5 + 7;
const int MXM = 1e5 + 7;
const int MX = 1e4 + 7;
const int maxbit = 18;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int pre[MX];
int m,n;
int find(int x)
{
	if(pre[x] == x) return x;
	return pre[x] = find(pre[x]);
}
bool same(int x,int  y)
{
	return find(x) == find(y);
}
void unionset(int x,int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 == f2) return;
	pre[f1] = f2;
}
struct node
{
	int u,v;
	int w;
}e[MX];
bool cmp(node a ,node b)
{
	return a.w < b.w;
}
void init()
{
	for(int i = 1;i <= n;++i) pre[i] = i;
	mem(e,0);
	m = 0;
}
int kruskal()
{
	int ans = 0;
	int cont = 0;
	sort(e+1,e+1+m,cmp);
	for(int i = 1;i <= m;++i)
	{
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		cont++;
		ans += e[i].w;
		if(cont == n-1) break;
	}
	return ans;
}
int main()
{
    while(cin >> n)
    {
    	if(!n) break;
    	init();
    	int T = n - 1;
    	while(T--)
    	{
    		char p;
    		getchar();
    		cin >> p;
    		int st = p - 'A' + 1;
    		int k;
    		cin >> k;
    		while(k--){
    			int ed;
    			int val;
    			cin >> p;
    			cin >> val;
    			ed = p - 'A' + 1;
    			e[++m].u = st;
    			e[m].v = ed;
    			e[m].w = val;
    		}
    	}
    	int ans = kruskal();
    	cout << ans << endl;
    }
    return 0;
}

B - Networking

POJ-1287

题意&&解法:本来也是裸题,唯一坑点在于该题中路的条数被描述为

The number of possible routes is unlimited.

所以就只能xjb开数组范围了
开5e3就过了

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MXN = 1e3 + 7;
const int MXM = 1e3 + 7;
const int MX = 1e2 + 7;
const int maxbit = 18;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int n,m;
struct node
{
    int from,to;
    int cost;
}a[5000];
int pre[55];
void init()
{
    for(register int i = 1; i <= n; ++i)
        pre[i] = i;
}
int found(int x)
{
    if(pre[x] == x) return x;
    return pre[x] = found(pre[x]);
}
bool same(int x,int y)
{
    return found(x) == found(y);
}
void unionset(int x,int y)
{
    int f1 = found(x);
    int f2 = found(y);
    if(f1 == f2) return;
    pre[f1] = f2;
}
bool cmp(node a,node b)
{
    return a.cost < b.cost;
}
int kruskal()
{
    int ans = 0;
    int cont = 0;
    sort(a+1,a+1+m,cmp);
    init();
    for(int i = 1; i <= m; ++i)
    {
        if(same(a[i].from,a[i].to))
            continue;
        unionset(a[i].from,a[i].to);
        ans += a[i].cost;
        cont ++;
        if(cont == n-1)
            break;
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        scanf("%d",&m);
        for(int i = 1; i <= m; ++i)
        {
            scanf("%d %d %d",&a[i].from,&a[i].to,&a[i].cost);
        }
        int ans;
        ans = kruskal();
        printf("%d\n",ans);
    }
    return 0;
}

C - Building a Space Station(待补)

D - Constructing Roads

POJ-2414

题意&&解法:给你一个图让你计算最小生成树,但有些路已经被修好了,所以其权值为0,需提前处理一下。
若用kruskal解决该题,则只需要将那些已经被修好的路提前加入最小生成树集合;
若用prim写,则只需要d[u][v] = d[v][u] = 0;

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MXN = 1e5 + 7;
const int MXM = 1e5 + 7;
const int MX = 1e4 + 7;
const int maxbit = 18;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int pre[MX];
int n;
struct node
{
	int u,v;
	int c;
}e[MX];
bool cmp(node a,node b)
{
	return a.c < b.c;
}
void init()
{
	for(int i = 1;i <= n;++i) pre[i] = i;
}
int find(int x)
{
	if(x == pre[x]) return x;
	return x = find(pre[x]);
}
bool same(int x,int y)
{
	return find(x) == find(y);
}
void unionset(int x,int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 == f2) return;
	pre[f1] =f2;
}
int kruskal()
{
	int m = n*n;
	int ans = 0;
	sort(e,e+m,cmp);
	for(int i = 0;i < m;++i)
	{
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		ans+=e[i].c;
	}
	return ans;
}
int main(int argc, char const *argv[])
{
	int p = 0;
	scanf("%d",&n);
	for(int i = 0;i < n;++i)
	{
		for(int j = 0;j < n;++j)
		{
			int w;
			scanf("%d",&w);
			e[p].u = i+1;
			e[p].v = j+1;
			e[p++].c = w;
		}
	}
	int q;
	scanf("%d",&q);
	init();
	while(q--)
	{
		int u,v;
		scanf("%d %d",&u,&v);
		unionset(u,v);
	}
	int ans = kruskal();
	printf("%d\n",ans);
	return 0;
}

E - QS Network

ZOJ-1586
题意&&解法:该题中在两个点之间连边的耗费是w + val[u] + val[v],所以只需要在建边的时候处理即可。

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MXN = 1e5 + 7;
const int MXM = 1e6 + 7;
const int MX = 1e4 + 7;
const int maxbit = 18;
//const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int n,m;
int pre[MX];
int val[MX];
struct node
{
	int u,v;
	int w;
}e[MXM];
void init()
{
	m = 0;
	for(int i = 1;i <= n;++i)
		pre[i] = i;
}
int find(int x)
{
	if(pre[x] == x) return x;
	return pre[x] = find(pre[x]);
}
bool same(int x,int y)
{
	return find(x) == find(y);
}
void unionset(int x,int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 == f2) return ;
	pre[f1] = f2;
	return ;
}
bool cmp(node a,node b)
{
	return a.w < b.w;
}
int kruskal()
{
	//printf("fuck\n");
	int cont = 0;
	int ans = 0;
	sort(e+1,e+1+m,cmp);
	for(int i = 1;i <= m;++i)
	{
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		ans += e[i].w;
		cont ++;
		if(cont == n-1) break;
	}
	return ans;
}
int main()
{
	int T;
	cin >> T;
    while(T--)
    {
    	cin >> n;
    	init();
    	for(int i = 1;i <= n;++i) cin >> val[i];
    	for(int i = 1;i <= n;++i)
    	{
    		for(int j = 1;j <= n;++j)
    		{
    			int k;
    			cin >> k;
    			if(j <= i) continue;
    			//printf("fuck\n");
    			e[++m].u = i;
    			e[m].v = j;
    			e[m].w = k + val[i] + val[j];
    		}
    	}
    	//printf("fuck\n");
    	int ans = kruskal();
    	//cout << m << endl;
    	cout << ans << endl;
    }
    return 0;
}

F - Truck History(待补)

G - Arctic Network

POJ-2349

题意&&解法
裸题

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MX = 5e2 + 7;
const int maxbit = 18;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
int n,m,k;
int pre[MX];
void init()
{
    for(register int i = 0;i < n;++i) pre[i] = i;
}
int found(int x)
{
    if(x == pre[x]) return x;
    return pre[x] = found(pre[x]);
}
bool same(int x,int y)
{
    return found(x) == found(y);
}
void unionset(int x,int y)
{
    int f1 = found(x);
    int f2 = found(y);
    if(f1 == f2) return;
    pre[f1] = f2;
}
struct node
{
    int from,to;
    double cost;
}e[MX*MX];
bool cmp(node a,node b)
{
    return a.cost < b.cost;
}
double kruskal()
{
    int cont = 0;
    double ans = -INF;
    init();
    sort(e,e+m,cmp);
    for(register int i = 0;i < m;++i)
    {
        if(same(e[i].from,e[i].to)) continue;
        if(cont == n - k) break;
        ans = max(ans,e[i].cost);
        unionset(e[i].from,e[i].to);
        cont ++;
    }
    return ans;
}
double cal(double x1,double y1,double x2,double y2)
{
    return sqrt((x1-x2)*(x1-x2) + (y1- y2) * (y1- y2));
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&k,&n);
        mem(e,0);
        double x[MX],y[MX];
        m = n*n;
        for(register int i = 0;i < n;++i)
        {
            scanf("%lf%lf",&x[i],&y[i]);
        }
        int c = 0;
        for(register int i = 0;i < n;++i)
        {
            for(register int j = 0;j < n;++j)
            {
                e[c].from = i;
                e[c].to = j;
                e[c++].cost = cal(x[i],y[i],x[j],y[j]);
            }
        }
        double ans = kruskal();
        printf("%.2f\n",ans);
    }
    return 0;
}

H - Highways

POJ-1715

题意&&解法
这题有两个值得注意的地方:

  1. 若用sort函数来排序double型的数据,当出现重复元素时,因为浮点误差的原因,会影响排序效率。
  2. 建边的时候最好去掉重边,即j = i + 1;

ACODE:

#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const int MX = 1e3 + 7 ;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
double cal(int x1,int y1,int x2,int y2)
{
	return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
int n,m;
int pre[MX];
int x[MX];
int y[MX];
int vis[MX][MX];
int p;
struct node
{
	int u,v;
	double w;
}e[MX*MX];
queue<node>q;
bool cmp(node a,node b)
{
	return a.w < b.w;
}
void init()
{
	for(int i = 1;i <= n;++i) pre[i] = i;
}
int find(int x){
	if(pre[x] == x) return x;
	return pre[x] = find(pre[x]);
}
bool same(int x,int y){
	return find(x) == find(y);
}
void unionset(int x,int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 == f2) return;
	pre[f1] = f2;
}
void kruskal()
{
	sort(e+1,e+1+p,cmp);
	for(int i = 1;i <= p;++i)
	{
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		q.push({e[i].u,e[i].v,0});
	}
	return;
}
int main()
{
	cin>>n;
	m = n*n;
	p = 0;
	for(int i = 1;i <= n;++i)
		cin>>x[i]>>y[i];
	for(int i = 1;i <= n;++i)
		for(int j = i+1;j <= n;++j)
		{
			e[++p].u = i;
			e[p].v = j;
			e[p].w = cal(x[i],y[i],x[j],y[j]);
		}
	int t;
	cin>>t;
	init();
	while(t--)
	{
		int u,v;
		cin>>u>>v;
		unionset(u,v);
	}
	kruskal();
	//if(q.empty()) cout<
	while(!q.empty())
	{
		node x = q.front();
		q.pop();
		cout<<x.u<<' '<<x.v<<endl;
	}
	return 0;
}

I - Agri-Net

POJ-1258

题意&&解法:裸题

ACODE:

//7777777
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lson l , m , rt << 1
#define rson m+1 , r , rt << 1 | 1
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const double eps = 1e-6;
const int MXN = 1e3 + 7;
const int MXM = 1e3 + 7;
const int MX = 1e2 + 7;
const int maxbit = 18;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
int n;
int cost[MX][MX];
int mincost[MX];
int used[MX];
int prim()
{
    for(int i = 0;i < n;++i)
    {
        mincost[i] = INF;
        used[i] = 0;
    }
    mincost[0] = 0;
    int ans = 0;
    while(1)
    {
        int v = -1;
        for(int u = 0;u < n;++u)
        {
            if(!used[u] && (v == -1||mincost[u] < mincost[v]))
                v = u;
        }
        if(v == -1) break;
        used[v]=1;
        ans +=mincost[v];
        for(int u = 0;u < n;++u)
        {
            mincost[u] = min(mincost[u],cost[v][u]);
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d",&n))
    {
        for(int i = 0;i < n;++i)
            for(int j = 0;j < n;++j)
                scanf("%d",&cost[i][j]);
        int ans = prim();
        printf("%d\n",ans);
    }
}

J - Borg Maze(待补)

K - The Unique MST

POJ-1679

题意&&解法
给你一个图,让你判断其最小生成树是否唯一(即是否存在多个耗费相同且都最小的生成树)
性质:次小生成树可由最小生成树换一条边得到
所以我们可以求其次小生成树,若和最小生成树耗费相同,则最小生成树不唯一。
我们先跑一遍kruskal记录下最小生成树的每一条边,然后再跑n-1次kruskal依次删除这n-1条边后(即遇到该边就跳过)的最小生成树(次小生成树)。坑点:此时还要判断一下是否能生成树。

ACODE:

#include
#include
#include
#include
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const double pi = 3.1415926535;
const int MX = 1e4 + 7 ;
const double val = pi/180.0;
const int INF = 0x3f3f3f3f;
int pre[MX];
int edge[MX];
int n,m;
struct node
{
	int u,v;
	int w;
	int id;
}e[MX];
bool cmp(node a,node b)
{
	return a.w < b.w;
}
void init()
{
	for(int i = 1;i <= n;++i) pre[i] = i;
}
int find(int x)
{
	if(pre[x] == x) return x;
	return x = find(pre[x]);
}
bool same(int x,int y)
{
	return find(x) == find(y);
}
void unionset(int x,int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 == f2) return ;
	pre[f1] =f2;
}

int kruskal()
{
	int p = 0;
	int ans = 0;
	init();
	sort(e,e+m,cmp);
	for(int i = 1;i <= m;++i)
	{
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		ans += e[i].w;
		edge[++p] = e[i].id;
	}
	return ans;
}
int kruskal2(int K)
{
	int cont = 0;
	int ans = 0;
	init();
	sort(e,e+m,cmp);
	for(int i = 1;i <= m;++i)
	{
		if(e[i].id == K) continue;
		if(same(e[i].u,e[i].v)) continue;
		unionset(e[i].u,e[i].v);
		ans += e[i].w;
		cont++;
	}
	if(cont != n-1) return -1;
	return ans;
}

int main(int argc, char const *argv[])
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(int i = 1;i <= m;++i)
		{
			cin>>e[i].u>>e[i].v>>e[i].w;
			e[i].id = i;
		}
		int ans = kruskal();
		int flag = 0;
		for(int i = 1;i <= n-1;++i)
		{
			int k = kruskal2(edge[i]);
			if(k == ans){
				flag = 1;
				break;
			}
		}
		if(flag){
			printf("Not Unique!\n");
		}
		else printf("%d\n",ans);
	}
	return 0;
}```


你可能感兴趣的:([kuangbin带你飞]专题六 最小生成树 解题报告)