NBUT 1914 asd的甩锅计划

题目描述
大家对hdu上面的畅通工程系列一定很熟悉了吧。比如如下一段,就是畅通工程里面其中一个题的叙述。
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
大家觉得这种情况一定很简单而且生活中遇不到吧。然而你错了!NBUT的书记yh就遇到了这么个头疼事:asd下达命令让村长去把村里的路修的高端大气上档次,简单说就是重新建路,可是村长又甩手把这事给了yh书记。然而现在一个大问题是:经费不够用!因此yh书记觉得不可能每家每户都有一条道路通往村里任意一家,只要能走到就行了(不管是直接到达还是先经过别人家这样的间接到达)。
NBUT是个有名的“坑”地方,不是地方坑,而是地方有坑,这样的话在那些有坑的地方修路和在平地上修路的价钱当然不一样啦。更坑的是,村长已经划好一些可能要修的路线了,你只能在这些线路上面选一些来修。比如说,尽管村长要修的路连着张三丰和李四收,这条路会经过一些坑,但是你决定修这条路的话不能绕过它,只能去填平,经费当然不一样啦,当然你也可以选择不去修这条路,只要能让村子里每户人家能相互到达就可以了。
现在yh书记已经知道村里有n户人家了,并且拿到村长给他的平面设计图,上面标明哪些路要修多长,和修这条路的费用,现在书记来请教你,完成镇里的任务最少需要修多长的路,和最少要花多少钱。书记是个爱民的人,希望村民能省力就省力,所以多花一些钱修更短的路是无所谓的,但是能完成这个任务当然还是能省钱就省钱。另外村长图里的起点终点相同的两条路是认为不一样的,可能按路线1建路比路线2减更短更省钱,谁知道呢~所以若是按照村长的图不能完成村里的任务,那么就输出“村长你家铺子烧啦”。
输入
每行两个整数n(1 <= n <= 1000),m (1 <= m <= 2e6+7),分别表示村里有多少户人家,和村长给的图里面的路线。
接下来m行,每行四个整数 a, b, c, d(1 <= a, b <= n, 1 <= c <= 1000, 1 <= d <= 1e9+7),分别表示农民a家到b家建一条路的话,长度是c,花费是d。
输出
对于每组数据,如果能满足建路要求,那么每行输出两个整数 length, cost,分别表示一共要修路的长度,和修路的花费,具体如题意描述。否则输出“村长你家铺子烧啦”。
样例输入
2 1
1 2 3 4
样例输出
3 4

题目大意:中文题目要认真看,有坑。

解题思路:其实就是普通的最小生成树。写cmp的时候先是保证len小的在前面,当len相等时,再考虑cos。还有就是输入的时候,会出现重边,而且重边的len和cos都不一样。跟cmp函数一样,要先取len小的,在len相等的情况下,取cos小的。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;

const int N = 2e6 + 10;
const int M = 1005;
typedef long long ll;
struct Node{
    int a, b;
    ll len, cos; 
}p[N];
int fa[M];
int n, m, cnt;
int get_fa(int x) {
    return x == fa[x] ? x : fa[x] = get_fa(fa[x]);
}
int cmp(Node x, Node y) {
    if (x.len != y.len) {
        return x.len < y.len;
    } else return x.cos < y.cos;
}
void kruskal(ll &len, ll &cos) {
    sort(p, p + cnt, cmp);
    len = cos = 0;
    for (int i = 0; i < cnt; i++) {
        int x = get_fa(p[i].a), y = get_fa(p[i].b);
        if (x != y) {
            fa[x] = y;
            len += p[i].len;
            cos += p[i].cos;
        }
    }
}
int vis[M][M];
void input() {
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= n; j++) {
            vis[i][j] = 0;  
        }   
    }   
    int a, b;
    ll l, c;
    for (int i = 0; i < m; i++) {
        scanf("%d %d %lld %lld", &a, &b, &l, &c);   
        if (vis[a][b]) {
            if (l < p[vis[a][b]].len) {
                p[vis[a][b]].len = l;
                p[vis[a][b]].cos = c;
            } else if (l == p[vis[a][b]].len) {
                if (c < p[vis[a][b]].cos) {
                    p[vis[a][b]].len = l;
                    p[vis[a][b]].cos = c;
                }   
            }
        }else {
            p[cnt++] = (Node){a, b, l, c};
            vis[a][b] = cnt - 1;
        }
    } 
}
int main() {
    while (scanf("%d %d", &n, &m) == 2) {
        for (int i = 0; i <= n; i++) fa[i] = i;
        cnt = 0;
        input();
        ll l, c;
        kruskal(l, c);
        int rec = get_fa(1), flag = 1;
        for (int i = 2; i <= n; i++) {
            if (get_fa(i) != rec) {
                flag = 0;
                break;  
            }   
        }
        if (!flag) printf("村长你家铺子烧啦\n");
        else printf("%lld %lld\n", l, c);
    }   
    return 0;
}