新的开始( [USACO08OCT]打井Watering Hole)

来源:互联网 发布:mysql 可以用check约束 编辑:程序博客网 时间:2024/04/30 21:06

新的开始
(newstart.pas/c/cpp)
【 题目描述】
话说小 FF 在经历了上次“寻找古代王族遗产” 的探险后, 成为了世界上最伟大的探险
家并拥有了一大笔财富。 当然他不能坐吃山空, 必须创造财富!! 于是他买下了传说中的
GreedIsland 并优先发展那里的采矿业„„他还将其称为 GreedIsland 的“ NewBe_One” 计划。
发展采矿业当然首先得有矿井, 小 FF 花了上次探险获得的千分之一的财富请人在岛上
挖了 N 口矿井, 但他似乎忘记考虑的矿井供电问题„„
为了保证电力的供应, 小 FF 想到了两种办法:
1、 在这一口矿井上建立一个发电站, 费用为 v( 发电站的输出功率可以供给任意多个
矿井)。
2、 将第 i 口矿井与已经有电力供应的第 j 口矿井之间建立电网的费用为 p[i,j]。
小 FF 希望身为”NewBe_One”计划首席工程师的你帮他想出一个保证所有矿井电力供应的最
小花费。
【 输入格式】
第一行一个整数 N,表示矿井总数。
第 2~N+1 行, 每行一个整数, 第 i 个数 v[i]表示在第 i 口矿井上建立发电站的费用。 接
下来为一个 N×N 的矩阵 P, 其中 p[i,j]表示在第 i 口矿井和第 j 口矿井之间建立电网的费用
( 数据保证有 p[i,j]=p[j,i],且 p[i,i]=0)。
【 输出格式】
输出共一行一个整数, 表示让所有矿井获得充足电能的最小花费。
【 输入样例】
4 5 4 4 3 0
2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
【 输出样例】
9
【 输出样例说明】
小 FF 可以选择在 4 号矿井建立发电站然后把所有矿井都与其建立电网, 总花费是
3+2+2+2=9。
【 数据规模】
对于 30%的数据: 1≤N≤50;
对于 100%的数据: 1≤N≤300; 1≤v[i],p[i,j]≤10^5;

这题看着没有任何头绪,但其实只是最小生成树。

这题看着没有任何头绪,但其实只是最小生成树。

这题看着没有任何头绪,但其实只是最小生成树。
先看张图!
这里写图片描述
我们可以这么想,岛上有一座另外的发电站p。
在x这个矿井造一个发电站,消耗w[i],就相当于x点到p点的消耗经费为w[i]
于是就可以构筑出上面那张图,上图求所有点相连的最小值不就是最小生成树吗?

code:

#include<bits/stdc++.h>using namespace std;int i,j,k,n,m,tot,ans,fa[305],w[305],f[305][305],top,re;int read(){    char c;while(c=getchar(),(c<'0'||c>'9')&&c!='-');    int x=0,y=1;if(c=='-') y*=-1;else x=c-'0';    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';     return x*y;}int find(int x){    if(fa[x]!=x) fa[x]=find(fa[x]);    return fa[x];}void unionn(int x,int y){    x=find(x);y=find(y);    if(x>y) fa[x]=y;    else fa[y]=x;}struct node{    int a,b,len;}a[100005];int cmp(node a,node b){    if(a.len<b.len) return 1;    else return 0;}int main(){    n=read();re=0;    for(int i=1;i<=n;i++) w[i]=read();    for(int i=1;i<=n;i++)     for(int j=1;j<=n;j++){        f[i][j]=f[j][i]=read();        if(j>=i+1) a[++top].a=i,a[top].b=j,a[top].len=f[i][j];     }    for(int i=1;i<=n+1;i++) fa[i]=i;    for(int i=1;i<=n;i++) a[++top].a=i,a[top].b=n+1,a[top].len=w[i];     sort(a+1,a+1+top,cmp);    for(int i=1;i<=top;i++){        if(find(a[i].a)!=find(a[i].b)){            k++;unionn(a[i].a,a[i].b);            ans+=a[i].len;        }        if(k==n) break;    }    cout<<ans;    return 0;}