poj1251------------------最小生成树(Prim)(a一送十)


第一次不用模板自己按理解写最小生成树。感觉很简单,但是真心被此题小陷阱恶心到了。

题是很简单,提交的时候无限RE。

以为是数组越界了,改了之后还是RE。

看了一下discuss看到大神提醒RE是因为可能每组数据后面有好多空格。(太变态了)

所以scanf是用字符接收会出错。

两种解决办法:一种用cin输入。一种是用字符串接收。


#include<stdio.h>
#define inf 100000
int a[110][110];
int vis[110];
int tree[110];
int main()
{
    int n, t, w, sum;
    int cnt, min, min_pos;
    char ch[10];
    while(scanf("%d", &n), n)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j]=0;
                else a[i][j] = inf;
        for(int i=0; i<n-1; i++)
        {
            scanf("%s%d", ch, &t);
            while(t--) {
                scanf("%s%d", ch, &w);
                a[i][ch[0]-'A'] = w;
                a[ch[0]-'A'][i] = w;        
            }       
        }
        sum = 0;
        cnt = 0;
        for(int i=0; i<n; i++) 
            vis[i] = 0;
        tree[0] = 0;
        vis[cnt++] = 1;
        while(cnt < n)
        {
            min = inf;
            min_pos = n;
            for(int i=0; i<cnt; i++) {
                for(int j=0; j<n; j++) {
                    if(a[tree[i]][j]<min && !vis[j]) {
                        min = a[tree[i]][j];
                        min_pos = j;                  
                    }        
                } 
            } 
            sum += min;
            tree[cnt++] = min_pos;
            vis[min_pos] = 1;         
        }
        printf("%d\n", sum);
    }
    return 0;    
}

2.

/*poj1287prim算法求最小生成树权值和*/
#include<stdio.h>
#define inf 10000
int a[100][100];
int vis[100];
int tree[100];
int main()
{
    int n, t, sum;
    int cnt, p, q, w, min, min_pos;
    while(scanf("%d", &n), n)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j] = 0;
                else a[i][j] = inf;
        
        scanf("%d", &t);
        while(t--) {
            scanf("%d %d %d", &p, &q, &w);
            if(w<a[p-1][q-1]) {
                a[p-1][q-1] = w;
                a[q-1][p-1] = w;              
            }
        } 
        for(int i=0; i<n; i++) 
            vis[i] = 0;
        sum = 0;
        tree[0] = 0;
        cnt = 1;
        vis[0] = 1;
        while(cnt < n) {
            min = inf;
            min_pos = n;
            for(int i=0; i<cnt; i++)
                for(int j=0; j<n; j++)
                    if(a[tree[i]][j]<min && !vis[j])
                    {
                        min = a[tree[i]][j];
                        min_pos = j;                     
                    }     
            tree[cnt++] = min_pos;
            vis[min_pos] = 1;
            sum += min;  
        }
        printf("%d\n", sum); 
    }
    return 0;
}

3.

/*poj1789prim算法求最小生成树权值和*/
#include<stdio.h>
#include<string.h>
#define inf 10000
char str[2010][10];
int a[2001][2001];
int vis[2001];
int tree[2001];
int main()
{
    int n, w;
    int cnt, sum, min, min_pos;
    while(scanf("%d", &n), n)
    {
        for(int i=0; i<n; i++)
            scanf("%s", str[i]);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j] = 0;
                else {
                    int t = 0;
                    for(int k=0; k<7; k++)
                        if(str[i][k] != str[j][k])
                            t++;
                    a[i][j] = t;
                    a[j][i] = t;
                }   
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = 0;
        cnt = 1;
        vis[0] = 1;
        int low_dis[2001]; //各个点到其他点的最短路 
        int s = 0;
        memset(low_dis, inf, sizeof(low_dis));
        while(cnt<n) 
        {
            min = inf; 
            for(int j=1; j<n; j++)  
            {  
                if(!vis[j] && a[s][j]<low_dis[j])  
                    low_dis[j] = a[s][j];  
                if(!vis[j] && low_dis[j]<min)  
                {  
                    min = low_dis[j];  
                    min_pos = j;      
                }  
            }              
            s = min_pos;
            vis[min_pos] = 1;
            sum += min;
            cnt++;
        }
        printf("The highest possible quality is 1/%d.\n", sum);
    }
    return 0;
} 

4.

这个题要注意有重边。

另外,题上有说每条边最大值为1000000000,所以我用了long long型。

wa了很多次,最后一次wa是因为代码中间部分定义的

long long low_dis[2001];

很难被发现,所以,以后还是在代码前段定义吧……

/*poj2395prim算法求最小生成树最大边*/
#include<stdio.h>
#include<string.h>
#define inf 1000000001
long long a[2001][2001];
int vis[2001];
int main()
{
    int n, m, p, q;
    long long w, sum, min, max;
    int cnt, min_pos;
    while(scanf("%d %d", &n, &m) != EOF)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j] = 0;
                else a[i][j] = inf;
        while(m--) {
            scanf("%d %d %lld", &p, &q, &w);
            if(w < a[p-1][q-1]) {
                a[p-1][q-1] = w;
                a[q-1][p-1] = w;              
            }          
        }
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = max = 0;
        cnt = 1;
        vis[0] = 1;
        long long low_dis[2001]; 
        int s = 0;
        memset(low_dis, inf, sizeof(low_dis));
        while(cnt<n) 
        {
            min = inf; 
            for(int j=1; j<n; j++)  
            {  
                if(!vis[j] && a[s][j]<low_dis[j])  
                    low_dis[j] = a[s][j];  
                if(!vis[j] && low_dis[j]<min)  
                {  
                    min = low_dis[j];  
                    min_pos = j;        
                }  
            }     
            if(min > max) max = min;         
            s = min_pos;
            vis[min_pos] = 1;
            sum += min;
            cnt++;
        }
        printf("%lld\n", max);
    }
    return 0;
} 

5.同上题

/*poj2485prim算法求最小生成树最大边*/
#include<stdio.h>
#include<string.h>
#define inf 1000000001
long long a[501][501];
int vis[501];
int main()
{
    int n, m;
    int sum, min, max;
    int cnt, min_pos;
    scanf("%d", &m);
    while(m--)
    {
        scanf("%d", &n);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d", &a[i][j]); 
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = max = 0;
        cnt = 1;
        vis[0] = 1;
        int low_dis[501]; 
        int s = 0;
        memset(low_dis, inf, sizeof(low_dis));
        while(cnt<n) 
        {
            min = inf; 
            for(int j=1; j<n; j++)  
            {  
                if(!vis[j] && a[s][j]<low_dis[j])  
                    low_dis[j] = a[s][j];  
                if(!vis[j] && low_dis[j]<min)  
                {  
                    min = low_dis[j];  
                    min_pos = j;        
                }  
            }     
            if(min > max) max = min;         
            s = min_pos;
            vis[min_pos] = 1;
            sum += min;
            cnt++;
        }
        printf("%d\n", max);
    }
    return 0;
} 

6.

用memset(low_dis, inf, sizeof(low_dis))时,其中的inf不可以太小,这道题我用时inf=100 001出现乱码,改为1 000 001结果才正确。

/*poj1258prim算法求最小生成树权值和*/
#include<stdio.h>
#include<string.h>
#define inf 1000001
int a[101][101];
int vis[101];
int low_dis[101];
int main()
{
    int n, sum, s;
    int min, min_pos, cnt;
    while(scanf("%d", &n) != EOF)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                scanf("%d", &a[i][j]);
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = 0;
        cnt = 1;
        s = 0;
        vis[0] = 1;
        memset(low_dis, inf, sizeof(low_dis));
        while(cnt < n) {
            min = inf;
            for(int i=1; i<n; i++)
            {
                if(!vis[i] && a[s][i]<low_dis[i])
                    low_dis[i] = a[s][i];
                if(!vis[i] && low_dis[i]<min)
                {    
                    min = low_dis[i];
                    min_pos = i;
                }     
            }           
            s = min_pos;
            vis[min_pos] = 1;
            cnt++;
            sum += min;
        }
        printf("%d\n", sum);                 
    }
    return 0;    
}

7.
/*poj2075prim算法求最小生成树权值和*/
#include<stdio.h>
#include<string.h>
char str[1100][21];
double a[1010][1010];
double vis[1010];
double low_dis[1010];
char tmp[21];
int main()
{
    int n, s, t, cnt, min_pos, tp, tq;
    double sum, min, cable, inf=10001.0, w;
    char p[21], q[21];
    scanf("%lf%d", &cable, &n);
    for(int i=0; i<n; i++)
        scanf("%s", str[i]);
    scanf("%d", &t);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            if(i == j) a[i][j] = 0.0;
            else a[i][j] = inf;
    while(t--)
    {     
        scanf("%s %s", p, q);
        for(int j=0; j<n; j++)
            if(!strcmp(p, str[j]))
            {
                tp = j;              
            } else if(!strcmp(q, str[j])) {
                tq = j;   
            }
        scanf("%lf", &w); 
        a[tp][tq] = w; 
        a[tq][tp] = w; 
    }
    for(int i=0; i<n; i++)
        vis[i] = 0;
    sum = 0;
    cnt = 1;
    s = 0;
    vis[0] = 1;
    for(int i=0; i<n; i++) low_dis[i]=inf;
    while(cnt < n) {
        min = inf;
        for(int i=1; i<n; i++)
        {
            if(!vis[i] && a[s][i]<low_dis[i])
                low_dis[i] = a[s][i];
            if(!vis[i] && low_dis[i]<min)
            {    
                min = low_dis[i];
                min_pos = i;
            }     
        }           
        s = min_pos;
        vis[min_pos] = 1;
        cnt++;
        sum += min;
    }
    if(cable - sum >= 0)
        printf("Need %.1lf miles of cable\n", sum);
    else printf("Not enough cable"); 
    getchar();
    getchar();
    return 0;    
}

8.

题意很难懂看懂,看了老半天词啊明白怎么回事,题之后就好写多了。

/*poj2349prim算法求最小生成树第k大边*/
#include<stdio.h>
#include<iostream>
using namespace std;
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
double a[501][501];
int vis[501];
double low_dis[501];
double ans[501];
int x[501], y[501];
int main()
{
    int t, k, n, p, min_pos, cnt, s;
    double sum, min, inf = 100001.0;
    scanf("%d", &t);
    while(t--) {
        scanf("%d %d", &k, &n);
        for(int i=0; i<n; i++)
            scanf("%d %d", &x[i], &y[i]);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j]=0.0;
                else a[i][j] = sqrt((double)((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])));     
        for(int i=0; i<n; i++)
        vis[i] = 0;
        sum = 0;
        cnt = 1;
        s = 0;
        vis[0] = 1;
        p = 0;
        for(int i=0; i<n; i++) low_dis[i]=inf;
        while(cnt < n) {
            min = inf;
            for(int i=1; i<n; i++)
            {
                if(!vis[i] && a[s][i]<low_dis[i])
                    low_dis[i] = a[s][i];
                if(!vis[i] && low_dis[i]<min)
                {    
                    min = low_dis[i];
                    min_pos = i;
                }     
            }           
            s = min_pos;
            vis[min_pos] = 1;
            cnt++;
            ans[p++] = min;
        }
        sort(ans, ans+p);
        for(int i=0; i<p; i++)
            if(n-1-i == k)
                printf("%.2lf\n", ans[i]);
    }
    return 0;
}

8.

wa了好多次。坐标村的时候用double存。我wa的原因竟然是inf定义的太小,没仔细看题啊。

/*poj3625prim算法求某些树边已知的最小生成树的其余树边之和*/
#include<stdio.h>
#include<iostream>
using namespace std;
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
double a[1001][1001];
int vis[1001];
double low_dis[1001];
double x[1001], y[1001];
int main()
{
    int t, k, n, p, min_pos, cnt, s, e, f;
    double sum, min, inf = 100000001.0;
    while(scanf("%d%d", &n, &t) != EOF)
    { 
        for(int i=0; i<n; i++)
            scanf("%lf %lf", &x[i], &y[i]);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j]=0.0;
                else a[i][j] = sqrt(((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))+0.0);     
        while(t--) {
            scanf("%d %d", &e, &f);
            a[e-1][f-1] = a[f-1][e-1] = 0.0;           
        }
        for(int i=0; i<n; i++)
        vis[i] = 0;
        sum = 0;
        cnt = 1;
        s = 0;
        vis[0] = 1;
        p = 0;
        for(int i=0; i<n; i++) low_dis[i]=inf;
        while(cnt < n) {
            min = inf;
            for(int i=1; i<n; i++)
            {
                if(!vis[i] && a[s][i]<low_dis[i])
                    low_dis[i] = a[s][i];
                if(!vis[i] && low_dis[i]<min)
                {    
                    min = low_dis[i];
                    min_pos = i;
                }     
            }           
            s = min_pos;
            vis[min_pos] = 1;
            cnt++;
            sum += min;
        }
        printf("%.2lf\n", sum);
    }
    return 0;
}

10.

三维坐标里求,说的很玄乎,其实很简单。

/*poj2031prim算法求最小生成树权值之和*/
#include<stdio.h>
#include<iostream>
using namespace std;
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
double a[101][101];
int vis[101];
double low_dis[101];
double x[101], y[101], z[101], r[101];
int main()
{
    int t, k, n, p, min_pos, cnt, s, e, f;
    double sum, min, inf = 100000001.0, tmp;
    while(scanf("%d", &n), n)
    { 
        for(int i=0; i<n; i++)
            scanf("%lf %lf %lf %lf", &x[i], &y[i], &z[i], &r[i]);
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j]=0.0;
                else {
                    tmp = ( sqrt( (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]) )-r[i]-r[j]);     
                    if(tmp>0) a[i][j] = tmp;
                    else a[i][j] = 0.0;
                }
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = 0.0;
        cnt = 1;
        s = 0;
        vis[0] = 1;
        for(int i=0; i<n; i++) low_dis[i]=inf;
        while(cnt < n) {
            min = inf;
            for(int i=1; i<n; i++)
            {
                if(!vis[i] && a[s][i]<low_dis[i])
                    low_dis[i] = a[s][i];
                if(!vis[i] && low_dis[i]<min)
                {    
                    min = low_dis[i];
                    min_pos = i;
                }     
            }           
            s = min_pos;
            vis[min_pos] = 1;
            cnt++;
            sum += min;
        }
        printf("%.3lf\n", sum);
    }
    return 0;
}

11.

样例是错的!!!!巨坑爹!!

要求输出最小生成树的最大树边,最小生成树的树边个数,以及各个树边。wa无数,prime最简单三层循环 tle 一次。最后换了两层循环,ac。

/*poj1861prim算法求最小生成树*/
#include<stdio.h>
#include<string.h>
#define inf 1000001
int a[1001][1001];
int vis[1001];
int x[1001], y[1001];
int tree[1001];
int main()
{
    int n, t, w, p, q;
    int cnt, sum, min, min_posx, min_posy, max;
    while(scanf("%d %d", &n, &t) != EOF)
    {
        for(int i=0; i<n; i++)
            for(int j=0; j<n; j++)
                if(i == j) a[i][j] = 0;
                else a[i][j] = inf;
        while(t--) {
            scanf("%d %d %d", &p, &q, &w);
            if(w < a[p-1][q-1])
                a[p-1][q-1] = a[q-1][p-1] = w;           
        }
        for(int i=0; i<n; i++)
            vis[i] = 0;
        sum = 0;
        cnt = 1;
        int r=0;
        max = 0;
        vis[0] = 1;
        int low_dis[2001];
        int low_dis_pos[2001]; 
        int s = 0;
        memset(low_dis, inf, sizeof(low_dis));
        while(cnt<n) 
        {
            min = inf; 
            for(int j=1; j<n; j++)  
            {  
                if(!vis[j] && a[s][j]<low_dis[j])  
                {
                    low_dis[j] = a[s][j];  
                    low_dis_pos[j] = s;
                }
                if(!vis[j] && low_dis[j]<min)  
                {  
                    min = low_dis[j];  
                    min_posx = low_dis_pos[j];
                    min_posy = j;        
                }  
            }              
            s = min_posy;
            vis[min_posy] = 1;
            cnt++;
            x[r] = min_posx;
            y[r++] = min_posy;  
            if(min > max) max = min;   
        }
        printf("%d\n%d\n", max, r);  
        for(int i=0; i<r; i++)
            printf("%d %d\n", x[i]+1, y[i]+1);
    }
    return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值