【作业存档】最小生成树的练习

本文记录了一次关于最小生成树作业的完成过程。在完成过程中,通过解决超时和错误,理解了如何在图中找到去掉一个点后保持其他点连接所需的最低成本。作业要求实现一个函数,计算在一个被破坏的网络中,如果失去一个城市,连接其余城市的最昂贵修复成本。通过等价关系算法解决了问题,同时注意到特殊情况——无法连通的情况。代码实现和问题解决过程详细描述,强调了连通性和成本效益的重要性。
摘要由CSDN通过智能技术生成

记,一次非常顺利的作业。

说是顺利,但其实也用了一个晚上,一边听公共关系学的课程,一边参与小组讨论,一边磕磕绊绊地写完了。当然没有一次通过所有测试点,反而是例子都没过,不过看了看代码发现了只是粗心的锅,自己的思路没大问题。

改了一下后运行超时+一个点没过,降低了时间复杂度后还是有一个点没过,最后看了一下别人的作业也顺利地改了过来。


目标是用函数实现,在一个图中去掉一个点后,记录下来其他点获得最小生成树需要将多少不在使用的边连通的权重最大的那个点,已知一组边的两个顶点、权重、是否在使用。

等价关系算法可以直接实现非常简单,主要是问题没有考虑会有不能连通的情况,


下为代码

#include<stdio.h>
#include<stdlib.h>

#define INF 0x7fffffff

typedef struct Road road;//直接把边存下来
struct Road{
    int V1,V2;
    int weight;
    int isUse;
};

int Init(road Graph1[],road Graph0[],int V,int E);
int FindCity(road Graph1[],road Graph0[], int finalV[], int V, int E1, int E0);

int Find(int V,int List[]);
void Union(int V1, int V2, int List[]);

int main(){
    int V, E, count = 0, i, E1;
    int *finalV;//因为V的个数不确定,所以用了动态分配内存
    road *Graph1, *Graph0;
    
    scanf("%d%d",&V,&E);
    Graph1 = (road*)malloc(sizeof(struct Road)*E);//存放目前在用的道路
    Graph0 = (road*)malloc(sizeof(struct Road)*E);//存放目前不在用的道路
    finalV = (int*)malloc(sizeof(int)*V);
    
    E1 = Init(Graph1, Graph0, V, E);//初始化道路
    
    count = FindCity(Graph1, Graph0, finalV, V, E1, E- E1);//找到最需要保护的城市
    
    for(i = 0; i < count - 1; i++){
        printf("%d ", finalV[i]+1);
    }
    if(count == 0)
        printf("0");
    else
        printf("%d", finalV[i]+1);
    
    free(finalV);
    free(Graph1);
    free(Graph0);
    return 0;
}

int Init(road Graph1[],road Graph0[],int V,int E){
    int i, E1 = 0, E0 = 0;
    int tmpV1,tmpV2, tmpWeight,isUse;
    for(i = 0; i < E; i++){
        scanf("%d%d%d%d", &tmpV1, &tmpV2, &tmpWeight, &isUse);
        if(isUse){
            Graph1[E1].V1 = tmpV1;
            Graph1[E1].V2 = tmpV2;
            Graph1[E1].weight = tmpWeight;
            Graph1[E1].isUse = isUse;
            E1++;
        }
        else{
            Graph0[E0].V1 = tmpV1;
            Graph0[E0].V2 = tmpV2;
            Graph0[E0].weight = tmpWeight;
            Graph0[E0].isUse = isUse;
            E0++;
        }
    }
    return E1;
}


int Find(int V,int List[]){//找到和V等价的那一堆数的代表点
    int tmpV = List[V];
    if (tmpV < 0)
        return V;
    while(List[tmpV] > 0){
        List[V] = List[tmpV];
        V = List[V];
        tmpV = List[tmpV];
    }
    return tmpV;
}

void Union(int V1, int V2, int List[]){//将包含V1和V包含2的两堆数合并
    int V1head = Find(V1, List), V2head = Find(V2,List);//先找到顶点
    if(List[V1head] > List[V2head]){//把size小的接到size大的上,代表点指向的内容为-size
        List[V2head] += List[V1head];
        List[V1head] = V2head;
    }
    else{
        List[V1head] += List[V2head];
        List[V2head] = V1head;
    }
}


int FindCity(road Graph1[],road Graph0[], int finalV[], int V, int E1, int E0){
    int i, tmpV, tmpE, costSum = 0, maxCost = 0, City = V;
    int *ConnectList;//用来记录联通情况
    int count = 0;
    
    //初始化联通情况
    ConnectList = (int*)malloc(sizeof(int)*V);
    
    for(tmpV = 0; tmpV < V; tmpV++){
        City = V - 1;//City用来判断是否获得最小生成树
        for(i = 0; i < V; i++)
            ConnectList[i] = -1;
        costSum = 0;
        for(tmpE = 0; tmpE < E1; tmpE++){
            if((Graph1[tmpE].V1 != (tmpV + 1)) && (Graph1[tmpE].V2 != (tmpV + 1))){//在这里出过错,忘了把自己去掉
                if(Find(Graph1[tmpE].V1 - 1, ConnectList) != Find(Graph1[tmpE].V2 - 1,ConnectList)){
                    Union(Graph1[tmpE].V1 - 1, Graph1[tmpE].V2 - 1, ConnectList);
                    City--;
                }
            }
        }
        for(tmpE = 0; tmpE < E0; tmpE++){
            if((Graph0[tmpE].V1 != (tmpV + 1)) && (Graph0[tmpE].V2 != (tmpV + 1)))
                if(Find(Graph0[tmpE].V1 - 1, ConnectList) != Find(Graph0[tmpE].V2 - 1,ConnectList)){
                    Union(Graph0[tmpE].V1 - 1, Graph0[tmpE].V2 - 1, ConnectList);
                    costSum += Graph0[tmpE].weight;
                    City--;
                }
        }
        if(City > 1)
            costSum = INF;
    
        if(costSum > maxCost){
            maxCost = costSum;
            count = 0;
            finalV[count] = tmpV;
            count++;
        }
        else if(costSum &&costSum == maxCost){
            finalV[count] = tmpV;
            count++;
        }

        
    }
    free(ConnectList);
        return count;
    
}

Battle Over Cities

It is vitally important to have all the cities connected by highways in a war. If a city is conquered by the enemy, all the highways from/toward that city will be closed. To keep the rest of the cities connected, we must repair some highways with the minimum cost. On the other hand, if losing a city will cost us too much to rebuild the connection, we must pay more attention to that city.

Given the map of cities which have all the destroyed and remaining highways marked, you are supposed to point out the city to which we must pay the most attention.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 2 numbers N (\le500), and M, which are the total number of cities, and the number of highways, respectively. Then M lines follow, each describes a highway by 4 integers: City1 City2 Cost Status where City1 and City2 are the numbers of the cities the highway connects (the cities are numbered from 1 to N), Cost is the effort taken to repair that highway if necessary, and Status is either 0, meaning that highway is destroyed, or 1, meaning that highway is in use.

Note: It is guaranteed that the whole country was connected before the war.

Output Specification:

For each test case, just print in a line the city we must protest the most, that is, it will take us the maximum effort to rebuild the connection if that city is conquered by the enemy.

In case there is more than one city to be printed, output them in increasing order of the city numbers, separated by one space, but no extra space at the end of the line. In case there is no need to repair any highway at all, simply output 0.

Sample Input 1:

4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 1 0

Sample Output 1:

1 2

Sample Input 2:

4 5
1 2 1 1
1 3 1 1
2 3 1 0
2 4 1 1
3 4 2 1

Sample Output 2:

0


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值