城市规划 蓝桥杯
最小生成树变种
题目的意思是:
栋栋居住在一个繁华的C市中,然而,这个城市的道路大都年久失修。市长准备重新修一些路以方便市民,于是找到了栋栋,希望栋栋能帮助他。
C市中有n个比较重要的地点,市长希望这些地点重点被考虑。现在可以修一些道路来连接其中的一些地点,每条道路可以连接其中的两个地点。另外由于C市有一条河从中穿过,也可以在其中的一些地点建设码头,所有建了码头的地点可以通过河道连接。
栋栋拿到了允许建设的道路的信息,包括每条可以建设的道路的花费,以及哪些地点可以建设码头和建设码头的花费。
市长希望栋栋给出一个方案,使得任意两个地点能只通过新修的路或者河道互达,同时花费尽量小。
输入的第一行包含两个整数n, m,分别表示C市中重要地点的个数和可以建设的道路条数。所有地点从1到n依次编号。
接下来m行,每行三个整数a, b, c,表示可以建设一条从地点a到地点b的道路,花费为c。若c为正,表示建设是花钱的,如果c为负,则表示建设了道路后还可以赚钱(比如建设收费道路)。
接下来一行,包含n个整数w_1, w_2, …, w_n。如果w_i为正数,则表示在地点i建设码头的花费,如果w_i为-1,则表示地点i无法建设码头。
输入保证至少存在一个方法使得任意两个地点能只通过新修的路或者河道互达。
思路:
从题目中我们可以看出如果只有路的话直接跑最小生成树就可以,如果加上河那么这里有个妙的想法就是把河也看成一个点,建立码头所花费的费用就是边的费用。所以跑两遍克鲁斯卡尔,不过还有个细节要注意就是如果边权为负数,这个边是不但不用花钱还会赚钱,那么就是必选,多多益善嘛~
所以代码如下:
#include <iostream> #include <cstring> #include <algorithm> #include <vector> using namespace std; const int N = 1e4+10; const int M = 2e5+10; int n,m; struct edge{ int from; int to; int c; edge(int from,int to,int c){ this->from=from; this->to=to; this->c=c; } bool operator < (const edge& e)const{ return this->c < e.c; } }; vector<edge> edges; int cost[N]; int fa[N]; int find(int a){ if(a==fa[a]){ return a; } return fa[a]=find(fa[a]); } int krske(){ for(int i=1;i<=n+1;i++)fa[i]=i; sort(edges.begin(),edges.end()); int res=0; int cnt=n-1; for(int i=0;i<edges.size();i++){ int u=edges[i].from; int v=edges[i].to; int c=edges[i].c; int fau=find(u); int fav=find(v); if(fau!=fav){ fa[fau]=fav; res+=c; cnt--; } else if(c<0) res+=c; } if(cnt==0){ return res; } return 0x3f3f3f3f; } int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ fa[i]=i; } for(int i=0;i<m;i++){ int a,b,c; cin>>a>>b>>c; edges.push_back(edge(a,b,c)); } int res1=krske(); for(int i=1;i<=n;i++){ int wi; cin>>wi; if(wi==-1){ continue; } edges.push_back(edge(i,n+1,wi)); } n++; int res2=krske(); cout<<min(res1,res2)<<endl; }

浙公网安备 33010602011771号