HDU 3080 The plan of city rebuild(prim和kruskal)

The plan of city rebuild

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 616    Accepted Submission(s): 215

Problem Description

News comes!~City W will be rebuilt with the expectation to become a center city. There are some villages and roads in the city now, however. In order to make the city better, some new villages should be built and some old ones should be destroyed. Then the
officers have to make a new plan, now you , as the designer, have the task to judge if the plan is practical, which means there are roads(direct or indirect) between every two villages(of course the village has not be destroyed), if the plan is available,
please output the minimum cost, or output"what a pity!".

Input

Input contains an integer T in the first line, which means there are T cases, and then T lines follow.

Each case contains three parts. The first part contains two integers l(0<l<100), e1, representing the original number of villages and roads between villages(the range of village is from 0 to l-1), then follows e1 lines, each line contains three integers a,
b, c (0<=a, b<l, 0<=c<=1000), a, b indicating the village numbers and c indicating the road cost of village a and village b . The second part first contains an integer n(0<n<100), e2, representing the number of new villages and roads(the range of village is
from l to l+n-1), then follows e2 lines, each line contains three integers x, y, z (0<=x, y<l+n, 0<=z<=1000), x, y indicating the village numbers and z indicating the road cost of village x and village y. The third part contains an integer m(0<m<l+n), representing
the number of deserted villages, next line comes m integers, p1,p2,…,pm,(0<=p1,p2,…,pm<l+n) indicating the village number.

Pay attention: if one village is deserted, the roads connected are deserted, too.

Output

For each test case, If all villages can connect with each other(direct or indirect), output the minimum cost, or output "what a pity!".

Sample Input

2
4 5
0 1 10
0 2 20
2 3 40
1 3 10
1 2 70
1 1
4 1 60
2
2 3
3 3
0 1 20
2 1 40
2 0 70
2 3
0 3 10
1 4 90
2 4 100
0

Sample Output

70
160

Author

wangjing

题目大意:先给你n1个点,m1条边,又给你n2个点,m2条边,然后告诉你有些点不需要,然后求剩下点的最

小生成树。反正光看题目就花了半小时,真不明白了,老路,新路,给边还分两次给。。

用了prim和kruskal两种算法来实现,中间还debug了蛮久。

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3080

Prim算法:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF =1e8;
int mp[205][205];
int des[205];
int visi[205];
int low[205];  //更新最小值
int n;

int prim()
{
    int i,j;

    memset(visi,0,sizeof(visi));
    for(i=0;i<=200;i++)
        low[i]=INF;
    int ans=0,pos=-1;
    for(i=0;i<n;i++)
    {
        if(!des[i])
        {
            pos=i;
            break;
        }
    }

    if(pos==-1) return 0;

    for(i=0;i<=200;i++)
        low[i]=mp[pos][i];

    visi[pos]=1;
    int mi;
    for(i=0;i<n;i++)
    {
        mi=INF;
        int flag=0;
        for(j=0;j<n;j++)
        {
            if(des[j]) continue;
            if(!visi[j])
            {
                flag=1;
                if(low[j]<mi)
                {
                    mi=low[j];
                    pos=j;
                }
            }
        }

        if(mi==INF&&flag)
            return -1;
        if(!flag) return ans;
        ans+=mi;
        visi[pos]=1;
        for(j=0;j<n;j++)
            if(!visi[j])
                low[j]=min(low[j],mp[pos][j]);
    }
    return ans;
}

int main()
{
    int tes,i,j,res;
    scanf("%d",&tes);

    while(tes--)
    {
        int n1,m,u,v,val;
        scanf("%d%d",&n1,&m);

        for(i=0;i<=200;i++)
            for(j=0;j<=200;j++)
                mp[i][j]=INF;
        memset(des,0,sizeof(des));
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            if(mp[u][v]>val)   //这个地方,边可能会多次给出,坑。。
            {
                mp[u][v]=val;
                mp[v][u]=val;
            }
        }
        int n2;
        scanf("%d%d",&n2,&m);
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            if(mp[u][v]>val)
            {
                mp[u][v]=val;
                mp[v][u]=val;
            }
        }
        n=n1+n2;
        int t,x;
        scanf("%d",&t);
        for(i=0;i<t;i++)
        {
            scanf("%d",&x);
            des[x]=1;
        }

        res=prim();
        if(res==-1) puts("what a pity!");
        else printf("%d\n",res);
    }
    return 0;
}

Kruskal算法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int INF =1e6;
const int maxn=205;

int n,m,t;   //总点数,总边数,desert的边数

int des[maxn];  //为1代表城市荒废
int fa[maxn];

struct Edge
{
    int from;
    int to;
    int val;
}edge[maxn*maxn];

int cmp(Edge p1,Edge p2)
{
    //if(des[p1.from]||des[p1.to]) return 0;
    //if(des[p2.from]||des[p2.to]) return 1;
    return p1.val<p2.val;
}

void init()
{
    for(int i=0;i<=200;i++)
        fa[i]=i;
}

int find1(int x)
{
    if(fa[x]!=x) fa[x]=find1(fa[x]);
    return fa[x];
}

void merge1(int p1,int p2)
{
    p1=find1(p1);
    p2=find1(p2);
    fa[p1]=p2;
}

int Kruskal()
{
    sort(edge,edge+m,cmp);
    int ans=0,ste=0;

    for(int i=0;i<m&&ste<n-t-1;i++)
    {
        int u=edge[i].from,v=edge[i].to,val=edge[i].val;
        if(des[u]||des[v]) continue;
        if(find1(u)!=find1(v))
        {
            ste++;
            ans+=val;
            merge1(u,v);
        }
    }

    if(ste==n-t-1) return ans;
    return -1;
}

int main()
{
    int tes,i,j,res;
    scanf("%d",&tes);

    while(tes--)
    {
        int n1,m1,u,v,val,n2,m2;
        scanf("%d%d",&n1,&m1);

        memset(des,0,sizeof(des));

        for(i=0;i<m1;i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            edge[i].from=u;
            edge[i].to=v;
            edge[i].val=val;
        }

        scanf("%d%d",&n2,&m2);
        n=n1+n2;
        m=m1+m2;

        for(i=m1;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&val);
            edge[i].from=u;
            edge[i].to=v;
            edge[i].val=val;
        }

        int x;
        scanf("%d",&t);
        for(i=0;i<t;i++)
        {
            scanf("%d",&x);
            des[x]=1;
        }

        init();
        res=Kruskal();

        //cout<<n<<" :n"<<endl;
        if(res==-1) puts("what a pity!");
        else printf("%d\n",res);
    }
    return 0;
}

时间: 2024-11-11 20:10:28

HDU 3080 The plan of city rebuild(prim和kruskal)的相关文章

HDU 3080 The plan of city rebuild(除点最小生成树)

题意  一个城市原来有l个村庄 e1条道路  又增加了n个村庄 e2条道路  后来后销毁了m个村庄  与m相连的道路也销毁了  求使所有未销毁村庄相互连通最小花费  不能连通输出what a pity! 还是很裸的最小生成树  把销毁掉的标记下  然后prim咯  结果是无穷大就是不能连通的 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N =

hdu 5290 Bombing plan(树形dp)

题目链接:hdu 5290 Bombing plan dpDestroy[u][i]表示以u为根节点的子树全部被摧毁,并且向上还可以破坏到距离u为i的城市:dpSafe[u][i]表示以u为根节点的子树中有距离u深度为i的城市还未被破坏. dpDestroy[u][i] = dpDestroy[v][i+1] + sum{ min(dpDestroy[k][j], dpSafe[k][j])(j≤i)| k为除了v以外的子节点} dpSafe[u][i] = dpSafe[v][i-1] + s

HDU 1162 Eddy&#39;s picture (最小生成树 prim)

题目链接 Problem Description Eddy begins to like painting pictures recently ,he is sure of himself to become a painter.Every day Eddy draws pictures in his small room, and he usually puts out his newest pictures to let his friends appreciate. but the res

最小生成树的两种算法:Prim和Kruskal算法

越来越明白了一个道理:你写不出代码的原因只有一个,那就是你没有彻底理解这个算法的思想!! 以前写过最小生成树,但是,水了几道题后,过了一段时间,就会忘却,一点也写不出来了.也许原因只有一个,那就是我没有彻底理解这两种算法. 主题: 其实,求最小生成树有两个要点,一个是权值最小,还有一个就是这个图必须是树.而Prim和Kruskal的不同之处在于两者选择的变量不同,Prim选择的是始终保持权值最小,然后逐个加点构建一棵树.而Kruskal则是始终保证是一棵树(虽然构建过程中不一定是真正的树,但并查

Prim和Kruskal最小生成树

标题: Prim和Kruskal最小生成树时 限: 2000 ms内存限制: 15000 K总时限: 3000 ms描述: 给出一个矩阵,要求以矩阵方式单步输出生成过程.要求先输出Prim生成过程,再输出Kruskal,每个矩阵输出后换行.注意,题中矩阵表示无向图输入: 结点数矩阵输出: Prim:矩阵输出 Kruskal:矩阵输出输入样例: 3 0 1 3 1 0 2 3 2 0 输出样例: 3 0 1 3 1 0 2 3 2 0Prim: 0 0 0 0 0 0 0 0 0 0 1 0 1

【图论】信手拈来的Prim,Kruskal和Dijkstra

关于三个简单的图论算法 prim,dijkstra和kruskal三个图论的算法,初学者容易将他们搞混,所以放在一起了. prim和kruskal是最小生成树(MST)的算法,dijkstra是单源最短路径的算法. prim 最小生成树prim算法采用了贪心策略:把点分成两个集合,A为已被处理(已经在最小生成树中)的顶点,B为待处理的顶点,(A,B)也就是一个割.若边(u,v)满足u∈A,v∈B,那么(u,v)就是通过割(A,B)的一条边. 很自然的,会有一定数量的边会通过该割,其中权重最小的边

Prim和Kruskal求最小生成树

Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小的一条边, 4.并把这条边.包括不在生成树的另一端点包括进生成树, …. 5.依次类推,直至将所有结点都包括进生成树为止 Pascal的渣渣代码... 注:寻找最短的边那一步可以用堆优化,但那样还不如直接用Kruskal...... Reference: http://www.nocow.cn/in

最小生成树 - Prim 和Kruskal

最近有些忙,先把最小生成树的代码挂上,有时间将讲解补上. 在这里两个函数:Prim和Kruskal函数,分别是这两个算法的主算法代码.使用的图存储方式是邻接矩阵. #include<iostream> #include<string.h> #include<queue> using namespace std; #define MAX 100 #define INT_MAX 10000 #define min(x,y)(x<y?x:y) typedef struc

HDU 1598 find the most comfortable road (枚举+Kruskal) 最短路

Problem Description XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级空中漫游结构)进行交流,每条SARS都对行驶在上面的Flycar限制了固定的Speed,同时XX星人对 Flycar的"舒适度"有特殊要求,即乘坐过程中最高速度与最低速度的差越小乘坐越舒服 ,(理解为SARS的限速要求,flycar必须瞬间提速/降速,痛苦呀 ), 但XX星人对时间却没那么多要求.要你找出一条城市间的最舒适的路径.(