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;
}

 

posted @ 2018-02-21 21:58  empty_road  阅读(165)  评论(0编辑  收藏  举报