[kuangbin带你飞]专题六 最小生成树 F~N

F - Truck History

 建图:每两个字符串之间的相同位置不同字符的个数

prim

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) a[i][j]=0;
        else a[i][j]=INF;
}
*/
const int N = 2000+10;
int tree[N];
int b[N];
int lowdis[N];
int a[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=a[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>a[next][j])
            lowdis[j]=a[next][j];//更新lowdis[]数组
        }
    }
    printf("The highest possible quality is 1/%d.\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) a[i][j]=0;
            else a[i][j]=INF;
    }
}
int main(){
    int i,j,k,t;
    char str[N][100];
	while(~ scanf("%d",&n))
	{
	    init();
		if(n == 0)
		break;
		for(i = 1;i<=n;i ++)
		{
			scanf("%s",str[i]);
			for(j = 1;j<=i;j ++)
			{
				t = 0;
				for(k = 0;k<7;k ++)
				{
					if(str[i][k]!=str[j][k])
					t ++;
					a[i][j] = a[j][i] = t;
				}
			}
		}
		begin_1 = 1;
        prime();
	}
    return 0;
}

G - Arctic Network

求最小生成树第K大(小)边的题目。

prim 中的lowdis【】数组对应输出就可以了

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
#include<math.h>
#include<algorithm>
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 500+10;
int tree[N];
double lowdis[N];
double map_1[N][N];
int n,m;
int begin_1;
int k;
void prime()
{
    int i,j,next;
    double Min,Mindis = 0;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    sort(lowdis+1,lowdis+1+n);
    printf("%.2f\n",lowdis[n-k+1]);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
struct node{
    double x,y;
}t1[N];
int main(){
    int t;
    cin>>t;
    while(t --)
    {

        cin>>k>>n;
        init();
        for(int i=1; i<=n; i++){
            cin>>t1[i].x>>t1[i].y;
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<i; j++)
            {

                    double xx = sqrt((t1[i].x-t1[j].x)*(t1[i].x-t1[j].x)+(t1[i].y-t1[j].y)*(t1[i].y-t1[j].y));
                    map_1[i][j] = map_1[j][i] = xx;
            }
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

H - Highways

 输出建边的路径

lowdis加个标记记录下,输出就可以了,加个fa【】数组同理,,v表示他的父亲节点是什么

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
#include<math.h>
#include<algorithm>
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 2000+10;
int tree[N];
//double lowdis[N];
double map_1[N][N];
int n,m;
int begin_1;
int k;
struct node{
    double len;
    int v;
}lowdis[N];
void prime()
{
    int i,j,next;
    double Min,Mindis = 0;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i].v = 1;
        lowdis[i].len=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    int cnt = 0;
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j].len)
            {
                Min=lowdis[j].len;//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j].len>map_1[next][j])
            {
                lowdis[j].len=map_1[next][j];//更新lowdis[]数组
                lowdis[j].v = next;
            }
        }
    }

    for(int i=1; i<=n; i++)
    {
        if(lowdis[i].len>0)
        printf("%d %d\n",i,lowdis[i].v);
    }
}
//void init(){
//    for(int i=1; i<=n; i++){
//        for(int j=1; j<=n; j++)
//            if(i==j) map_1[i][j]=0;
//            else map_1[i][j]=INF;
//    }
//}
struct node1{
    double x,y;
}t1[N];
int main(){
    scanf("%d",&n);
    {
//        init();
        for(int i=1; i<=n; i++){
            scanf("%lf%lf",&t1[i].x,&t1[i].y);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<i; j++)
            {
                    double xx = sqrt((t1[i].x-t1[j].x)*(t1[i].x-t1[j].x)+(t1[i].y-t1[j].y)*(t1[i].y-t1[j].y));
                    map_1[i][j] = map_1[j][i] = xx;
            }
        }
        int m;
        scanf("%d",&m);
        while(m --)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            map_1[x][y] = map_1[y][x] = -1;
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

I - Agri-Net

 模板,,直接套就可以了

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 1000+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
int main(){
    while(cin>>n && n)
    {
        init();
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&map_1[i][j]);
            }
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

J - Borg Maze

最小生成树+BFS

题意:n*m的矩阵,空格代表可以走,#表示墙,A和S代表其中的点

建图:把图中各个字母之间的BFS的路径值存为边权值,

bfs,,坑,,

vj交不了,去poj交的

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <algorithm>
using namespace std;
#define mem(a,b) memset(a,(b),sizeof(a))
#define CL(a, b) memset(a, b, sizeof(a))
#define debug(x) cout<<"debug"<<x<<"\n"
#define sc scanf
#define pr printf
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll long long
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
const int N = 2600+10;
struct node{
    int x,y,step;
};
queue<node>mmp;
int a[60][60];
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
char maze[60][60];
int vis[60][60];
int dir[][4]={{-1,0},{0,-1},{0,1},{1,0}};
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    memset(lowdis,0,sizeof(lowdis));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
void init_vis(int n1,int m1)
{
    for(int i=0; i<n1; i++)
    {
        for(int j=0; j<m1; j++)
        {
            if(maze[i][j] == '#')
            {
                vis[i][j] = 1;
            }
            else
            {
                vis[i][j] = 0;
            }
        }
    }
}
void bfs(int x,int y)
{
    int u,v;
    while(!mmp.empty())
    {
        mmp.pop();
    }
    node qq;
    qq.x = x;
    qq.y = y;
    qq.step = 0;
    u = a[x][y];
    vis[x][y] = 1;
    mmp.push(qq);
    while(!mmp.empty())
    {
        node mm;
        int xx,yy,ss;
        mm = mmp.front();
        mmp.pop();
        xx = mm.x;
        yy = mm.y;
        ss = mm.step;
        if(a[xx][yy] != -1)
        {
            v = a[xx][yy];
            map_1[u][v] = ss;
        }
        for(int i=0; i<4; i++)
        {
            if(!vis[xx+dir[i][0]][yy+dir[i][1]])
            {
                mm.x = xx+dir[i][0];
                mm.y = yy+dir[i][1];
                mm.step = ss+1;
                vis[mm.x][mm.y] = 1;
                mmp.push(mm);
            }
        }
    }
}
int main()
{

    int t;
    scanf("%d",&t);
    int n1,m1;
    while(t --)
    {
        int cnt = 0;
        memset(a,-1,sizeof(a));
        scanf("%d%d",&m1,&n1);
        gets(maze[0]);//就是这里,我把它换成fflush(stdin)就不行
        for(int i=0; i<n1; i++)
        {
            gets(maze[i]);
            for(int j=0; j<m1; j++)
            {
                if(maze[i][j] == 'A' || maze[i][j] == 'S')
                {
                    a[i][j] = ++cnt;
                }
            }
        }
        n = cnt;
        init();
        for(int i=0; i<n1; i++)
        {
            for(int j=0; j<m1; j++)
            {
                if(a[i][j] != -1)
                {
                    init_vis(n1,m1);

                    bfs(i,j);
                }
            }
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

K - The Unique MST

 次小生成树(模板题)

题意:判断最小生成树是否唯一

最小生成树的结果和次小生成树的结果比对就,可以判断最小生成树是否唯一

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 200+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
/*新开的*/
int Max[N][N]; //Max[i][j]表示在最小生成树中从i到j的路径中的最大边权
bool used[N][N];
int pre[N];
int MST,_MST;
int ans ;
int prime()
{
    int i,j,Min,Mindis=0,next;
    for(i=1;i<=n;i++)
    {
        pre[i] = 1;
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    pre[begin_1] = -1;
    for(i=1;i<n;i++)
    {
        Min=INF;
        int p = -1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                p = j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[p]=1;
        used[p][pre[p]] = used[pre[p]][p] = false;
        for(j=1;j<=n;j++)
        {
            if(tree[j])
            {
                Max[j][p] = Max[p][j] = max(Max[pre[p]][j],lowdis[p]);
            }
            else
            {
                if(map_1[p][j]<lowdis[j])
                {
                    lowdis[j] = map_1[p][j];
                    pre[j] = p;
                }
            }
        }
    }
    return Mindis;
}
int second_prim()
{
    int ans=INF;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            if(used[i][j]) ans=min(ans,MST+map_1[i][j]-Max[i][j]);
    return ans;
}
void init(){
    memset(tree,0,sizeof(tree));
    memset(used,false,sizeof(used));
    memset(Max,-1,sizeof(Max));
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--)
    {

        int m;
        scanf("%d%d",&n,&m);
        init();
        for(int i=0; i<m; i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            map_1[a][b]=map_1[b][a]=c;
            used[a][b]=used[b][a]=true;
        }
        begin_1 = 1;
        MST=prime();
        _MST=second_prim();
        if(MST==_MST) printf("Not Unique!\n");
        else printf("%d\n",MST);
    }
    return 0;
}

L - 还是畅通工程

 模板题:

#include<stdio.h>
#include<iostream>
#include<string.h>
#define INF 0x3f3f3f3f
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 100+10;
int tree[N];
int lowdis[N];
int map_1[N][N];
int n;
int begin_1;
void prime()
{
    int i,j,Min,Mindis=0,next;
    memset(tree,0,sizeof(tree));
    for(i=1;i<=n;i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1;i<n;i++)
    {
        next = -1;
        Min=INF;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1;j<=n;j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
            lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    printf("%d\n",Mindis);
}
void init(){
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}
int main(){
    while(cin>>n && n)
    {
        init();
        for(int i=1; i<=n*(n-1)/2; i++){
            int a,b,c;
            cin>>a>>b>>c;
            map_1[a][b] = map_1[b][a] = min(map_1[a][b],c);
        }
        begin_1 = 1;
        prime();
    }
    return 0;
}

M - Jungle Roads

 同A题

N - 畅通工程再续

 模板题

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#define INF 1000000.0
using namespace std;
/*
*  数组tree[]用来记录最小生成树的节点
*  数组lowdis[]记录从起点到其余所有点的距离并不断更新
*  数组map[][]记录所有数据两点之间的距离
*  n是所有节点的数目,begin_1是起点
*  Mindis是最小生成树的长度
主函数中输入前需要:
for(int i=1; i<=n; i++)
{
    for(int j=1; j<=n; j++)
        if(i==j) map_1[i][j]=0;
        else map_1[i][j]=INF;
}
*/
const int N = 200+10;
int tree[N];
double lowdis[N];
double map_1[N][N];
int n;
int begin_1;
double prime()
{
    int i,j,next;
    double Mindis=0;
    memset(tree,0,sizeof(tree));
    for(i=1; i<=n; i++)
    {
        lowdis[i]=map_1[begin_1][i];//用lowdis[]数组记录下从起点到剩下所有点的距离
    }
    tree[begin_1]=1;//标记起点(即最小生成树中的点)
    for(i=1; i<n; i++)
    {
        double Min=INF;
        int next = -1;
        for(j=1; j<=n; j++)
        {
            if(!tree[j]&&Min>lowdis[j])
            {
                Min=lowdis[j];//求出从当前起点到其余所有点的距离中最短的
                next=j;
            }
        }
        Mindis+=Min;//记录下整条最小树的长度
        tree[next]=1;
        for(j=1; j<=n; j++)
        {
            if(!tree[j]&&lowdis[j]>map_1[next][j])
                lowdis[j]=map_1[next][j];//更新lowdis[]数组
        }
    }
    return Mindis;
}
void init()
{
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
            if(i==j) map_1[i][j]=0;
            else map_1[i][j]=INF;
    }
}

struct point
{
    double x,y;
} p[N];
double len(point a,point b)
{
    double x=a.x-b.x;
    double y=a.y-b.y;
    return sqrt(x*x+y*y);
}
int main()
{
    int t;
    //freopen("N.txt","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        init();
        for(int i=1; i<=n; i++)
        {
            scanf("%lf %lf",&p[i].x,&p[i].y);
            for(int j=1; j<i; j++)
            {
                double Len=len(p[i],p[j]);
                if(Len>=10&&Len<=1000)	map_1[i][j]=map_1[j][i]=Len;
            }
        }
        begin_1 = 1;
        double ans=prime();
        if(ans!=INF)
        {
            printf("%.1f\n",ans*100);
        }
        else
        {
            printf("oh!\n");
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值