このトピックでは
、特定の地域の都市交通状況の調査について説明し、既存の町間高速道路の統計を取得し、「ブロックされていないプロジェクト」の目標を提唱します。それは、地域全体の任意の2つの町間の迅速な輸送を可能にすることです(ただし、必ずしもそうとは限りません。直接高速道路は、高速道路を介して間接的に到達可能である限り、接続されています。都市道路の統計表が利用可能になりました。この表には、任意の2つの都市間に高速道路を建設するコストと、道路が完成したかどうかのステータスが一覧表示されます。次に、地域全体のスムーズな交通に必要な最小コストを計算するプログラムを作成してください。
入力形式:入力
の最初の行は村の数N(1≤N≤100)を示します。次のN(N-1)/ 2行は、村間の道路のコストと建設状況に対応します。各行は4つの正の値を示します。整数、2つの村の数(1からNまでの番号)、2つの村の間の道路のコスト、および建設状況です。1は建設済み、0は建設なしを意味します。
出力形式:
州の円滑な流れに必要な最低コストを出力します。
入力例:
4
1 2 1 1
1 3 4 0
1 4 1 1
2 3 3 0
2 4 2 1
3 4 5 0
出力例:
3
サンプルの入出力分析の概略図:
サンプルは上の図に抽象化できます。実線は2つの村の間の道路が建設され、点線は2つの村の間の道路が建設されていないことを表します。明らかに、上の図では、滑らかな道路が最小全域木です。n個の頂点を含むグラフの最小全域木には、n個の頂点とn-1個のエッジが必要であることがわかっています。この例に対応するのは、4つの頂点と3つのエッジです。この質問では、クラスカルアルゴリズムのアイデアを使用して最小スパニングツリーを構築します。
この例の最小全域木を次の図に示します
。2つの画像を比較すると、例の出力がわかります。3は、頂点2と頂点3の間の未舗装道路のコストです。
問題解決のアイデア:入力データを並べ替えることができます。データの入力グループの状態が同じである場合、同じ状態のデータはキーワードコストに従って昇順で並べ替えられます。データの入力グループの状態が異なる場合、それらは次のように降順で並べ替えられます。キーワードstatestateのサイズ。
次の図に示すように、サンプル入力データが並べ替えられます:
次に、クラスカルアルゴリズムのアイデアを使用して、最小スパニングツリーを構築します(クラスカルアルゴリズムでは、ユニオン検索を使用して、最小スパニングにループがないことを確認しますツリー)...(特定の手順のセクションのコードを参照してください)。
参照回答:
#include <stdio.h>
#include <stdlib.h>//qsort()函数的头文件。
#define MAXVERTEXNUM 101//村庄数目N (1≤N≤100)
#define MAXEDGENUM 4951//N(N−1)/2行,当N=100时,有100*99/2=4950行数据。
/*typedef定义新的数据类型,相当于给该结构体取了一个别名,该结构体类型即Road类型;
与此同时,定义了一个结构体指针,其名为road,指向该结构体。
结构体中的成员v1代表道路连接的两个村庄中其中一个村庄的编号,
v2代表道路连接的两个村庄中另外一个村庄的编号,
cost代表两村庄间道路的成本,
state代表两村庄间道路的修建状态。*/
typedef struct{
int v1;
int v2;
int cost;
int state;
}Road,*road;
Road a[MAXEDGENUM];//定义一个Road类型的数组,其名为a。
int parent[MAXVERTEXNUM];//定义一个int类型的数组,其名为parent。
/*qsort()比较函数,如果输入的各组数据之间的状态相同,
则在相同状态的数据间按关键字cost进行升序排序;
如果输入的各组数据之间的状态不同,则按照关键字状态state的大小进行降序排序。*/
int cmp(const void *a,const void *b)
{
road pa=(road)a;
road pb=(road)b;
int num1=pa->cost;
int num2=pb->cost;
int t1=pa->state;
int t2=pb->state;
if(t1==t2)
return num1-num2;
else
return t2-t1;
}
/*并查集之初始化操作*/
void init(int n)
{
int i;
for(i=1;i<=n;i++)
parent[i]=i;//村庄编号从1到N,将每个顶点(城镇)的父结点设置为自己。
}
/*并查集之寻找根节点操作*/
int find_root(int x)
{
if(x==parent[x])//如果该元素的父结点是其自己,则说明该元素为根结点,返回该元素的编号。
return x;
else
/*否则递归地去寻找该元素的根结点,
递归操作顺便把从根到该结点路径上的所有结点都直接放到根节点下。*/
return parent[x]=find_root(parent[x]);//压缩路径。
//补充:压缩路径的好处:有可能降低了树高,提高以后的查询效率。
}
int main()
{
int N,M,i,sum=0;
scanf("%d",&N);//输入数据村庄数目N (1≤N≤100)。
M=N*(N-1)/2;//用变量M存储接下来有多少行数据。*******注意这边的(乘号)。
for(i=0;i<M;i++)
{
scanf("%d%d%d%d",&a[i].v1,&a[i].v2,&a[i].cost,&a[i].state);
/*每行给出4个正整数,分别是两个村庄的编号(从1编号到N),
此两村庄间道路的成本,以及修建状态——1表示已建,0表示未建。*/
}
qsort(a,M,sizeof(Road),cmp);//qsort()函数对a数组进行排序。*/
init(N);//初始化操作。
for(i=0;i<M;i++)
{
/*查找连通村庄的道路连接的其中一个村庄的父结点
和另外一个村庄的父结点。如果它们的父结点不同,
则将其中一个村庄的父结点A的父结点设置成另一个村庄的父结点B,
如果该条道路未建,则将该条道路的成本加入到变量sum中。(kruskal算法的主体部分)*/
int A=find_root(a[i].v1);
int B=find_root(a[i].v2);
if(A!=B)
{
parent[A]=B;
if(a[i].state==0)
sum+=a[i].cost;
}
}
printf("%d",sum);//输出全省畅通需要的最低成本。
return 0;
}
この質問は、クラスカルアルゴリズムテンプレートをわずかに変更するだけでよく、比較的基本的な質問です。
もうナンセンスではありません、また会いましょう!