airplane
Problem.Airplane
Input file: airplane.in
Output file: airplane.out
Time limit: 1 second
cky 公司的运营蒸蒸日上,由于出差实在太频繁,而且坐汽车有些太慢了,所以cky 想要顺势直接进驻航空
业。cky 所在的国家天朝有n 个城市,m 个航空公司,每两个城市之间可能有一条航线运营(双向),总共
有k 条航线,每条航线都属于某一航空公司。现在cky 希望收购一家航空公司(为了涉及航空业以及防垄断,
cky 必须且只能购买一家航空公司),使得他能通过飞机从任意城市到达目标的城市(允许转机),当然很可能
没有一家公司能满足cky 的要求,所以cky 还需收购其他公司掌控的航线。每个航空公司都有一个市值,每
条航线都有一个收购价。现在cky 想知道他最少需要花费多少钱。
Input
第1 行,3 个整数n; m; k,表示城市数量,航空公司数和航线数。城市用1; 2; : : : ; n 编号。
接下来一行,一共m 个整数,第i 个整数ai 表示第i 个航空公司的市值。接下来k 行,每行4 个整数
ui; vi; costi; bi,表示第i 条航线连接城市u; v,价值cost i,所属航空公司为bi
题目保证u! = v
题目保证有解。
Output
输出最少需要花费多少钱
Sample
airplane.in
4 3 3
airplane.out
100 150 200
1 2 100 1
1 3 160 2
1 4 220 3
460
Note
• 对于50% 的数据,1 <= n <= 1000,1 <= m <= 1000,1 <= k <= 10000;
• 对于100% 的数据,1 <= n <= 2000,1 <= m <= 2000,1 <= k <= 200000,1 <= bi <= m,1 <= costi; ai <= 10^8。
题解:
这道题就是求最小生成树,但是有一点小技巧,如果每次都直接用克鲁斯卡尔算法,则时间复杂度会是O( km ),所以需要优化,我们可以发现,我们第一次先做一次克鲁斯卡尔算法,那么我们以后的边只能在第一次选好的边里选,所以现在我们的时间复杂度变成了O( nm )。
代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int N=4001; const int M=200001; int tot,n,m,k,cnt; long long ans=1ll<<60; int father[N],head[N],w[N]; struct node{ int x,y; long long va; }a[M],use[M]; struct edge{ int x,y,next; }e[M]; bool cmp(const node &e,const node &b){ return e.va<b.va; } void add(int u,int v,int bl){ tot++; e[tot].y=v; e[tot].x=u; e[tot].next=head[bl]; head[bl]=tot; } int find(int x){ if (x==father[x]) return x; else return father[x]=find(father[x]); } int main(){ freopen("airplane.in","r",stdin); freopen("airplane.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=m;i++) scanf("%I64d",w+i); for (int i=1;i<=k;i++){ int u,v,bl; long long val; scanf("%d%d%I64d%d",&u,&v,&val,&bl); a[i]=(node){u,v,val}; add(u,v,bl); } sort(a+1,a+k+1,cmp); for (int i=1;i<=n;i++) father[i]=i; for (int i=1;i<=k;i++){ int r1=find(a[i].x); int r2=find(a[i].y); if (r1!=r2){ father[r2]=r1; use[++cnt]=a[i]; } } for (int i=1;i<=m;i++){ for (int j=1;j<=n;j++) father[j]=j; for (int j=head[i];j;j=e[j].next){ int r1=find(e[j].x); int r2=find(e[j].y); if (r1!=r2) father[r2]=r1; } long long num=0; for (int j=1;j<=cnt;j++){ int r1=find(use[j].x); int r2=find(use[j].y); if (r1!=r2){ father[r2]=r1; num+=use[j].va; } } if(num+w[i]<ans) ans=num+w[i]; } printf("%I64d",ans); return 0; }