[USACO3.2] Sweet Butter(java API + spfa)

Sweet Butter
Greg Galperin – 2001
Farmer John has discovered the secret to making the sweetest butter in all of Wisconsin: sugar. By placing a sugar cube out in the pastures, he knows the N (1 <= N <= 500) cows will lick it and thus will produce super-sweet butter which can be marketed at better prices. Of course, he spends the extra money on luxuries for the cows.

FJ is a sly farmer. Like Pavlov of old, he knows he can train the cows to go to a certain pasture when they hear a bell. He intends to put the sugar there and then ring the bell in the middle of the afternoon so that the evening’s milking produces perfect milk.

FJ knows each cow spends her time in a given pasture (not necessarily alone). Given the pasture location of the cows and a description of the paths the connect the pastures, find the pasture in which to place the sugar cube so that the total distance walked by the cows when FJ rings the bell is minimized. FJ knows the fields are connected well enough that some solution is always possible.

PROGRAM NAME: butter
INPUT FORMAT
Line 1: Three space-separated integers: N, the number of pastures: P (2 <= P <= 800), and the number of connecting paths: C (1 <= C <= 1,450). Cows are uniquely numbered 1…N. Pastures are uniquely numbered 1…P.
Lines 2…N+1: Each line contains a single integer that is the pasture number in which a cow is grazing. Cow i’s pasture is listed on line i+1.
Lines N+2…N+C+1: Each line contains three space-separated integers that describe a single path that connects a pair of pastures and its length. Paths may be traversed in either direction. No pair of pastures is directly connected by more than one path. The first two integers are in the range 1…P; the third integer is in the range (1…225).
SAMPLE INPUT (file butter.in)

3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5

INPUT DETAILS
This diagram shows the connections geometrically:

p2
P1 @–1--@ C1
\ |
\ |
5 7 3
\ |
| \ C3
C2 @–5--@
P3 P4
OUTPUT FORMAT
Line 1: A single integer that is the minimum distance the cows must walk to a pasture with a sugar cube.
SAMPLE OUTPUT (file butter.out)
8

OUTPUT DETAILS:

Putting the cube in pasture 4 means: cow 1 walks 3 units; cow 2 walks 5
units; cow 3 walks 0 units – a total of 8.

翻译
Farmer John 发现了做出全威斯康辛州最甜的黄油的方法:糖。

把糖放在一片牧场上,他知道 N 只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。

Farmer John 很狡猾。像以前的 Pavlov,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。

Farmer John 知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)。

输入格式
第一行包含三个整数 N,P,C,分别表示奶牛数、牧场数和牧场间道路数。

第二行到第 N+1 行,每行一个整数,其中第 i 行的整数表示第 i-1 头奶牛所在的牧场号。

第 N+2 行到第 N+C+1 行,每行包含三个整数 A,B,D,表示牧场号为 A 和 B 的两个牧场之间有一条长度为 D 的双向道路相连。

输出格式
输出一行一个整数,表示奶牛必须行走的最小的距离和。

输入输出样例

输入
3 4 5
2
3
4
1 2 1
1 3 5
2 3 7
2 4 3
3 4 5

输出
8

说明/提示
数据范围

对于所有数据,1≤N≤500,2≤P≤800,1≤A,B≤P,1≤C≤1450,1≤D≤255。

样例解释

作图如下:

p2
P1 @–1--@ C1
|
|
5 7 3
|
| C3
C2 @–5--@
P3 P4
把糖放在4号牧场最优。

在USACO上找了道图论题做做

这个题目还挺有意思的,与一般的求最短路模板题不大一样,题意理解了好办

题意:这个题目相当于在无向图中找到一个点作为起点,每头牛在它所在的牧场从最短路径走过来,算出这些牛总共走的距离之和(单源最短路),但是起点可以是图上任意一点,因此要遍历图上所有起点,则转化成了多源最短路问题,找到使所有牛距离之和最小的一个,输出距离之和最小值

从本题的数据范围可以知道用floyd(O(n^3))会超时,可以选择堆优化版dijkstra(O(nmlogn))或者spfa(最坏情况O(mn ^2)),可以发现,由于是多源汇,后两个算法的时间复杂度要在原基础上乘n。

思路:

让spfa返回所有奶牛到目标的距离之和,

并循环spfa取最小值,传入spfa函数的参数是起点编号。

spfa函数末尾返回每头牛到目标的距离之和

这次尝试用java做,感觉java的写法比c++复杂多了,而且运行速度也比后者慢的多,搞算法竞赛的还是不建议用这个(但java也有一些优势),除非纯粹是为了练练java。。

本题运用了javaAPI的ArrayList,ArrayDeque,分别对应c++STL的不定数组vector和循环队列queue

//package cn.edu.hncu_06;

//import com.sun.jmx.remote.internal.ArrayQueue;
import java.util.ArrayDeque;//API Queue(循环队列)对应STL的queue
import java.util.ArrayList;//在Java中,ArrayList类对应c++STL的vector。
import java.util.Arrays;//包含可对java的数组进行操作的函数:如Arrays.fill()

import java.util.Scanner;

public class Main {

    static final int N = 500+10;
    static final int P = 800+10;
    static final int C = 3000+10;//无向边 2*1450直接开3000
    static int n,p,c;
    static int[] h = new int[P];
    static int[] e = new int[C];
    static int[] ne = new int[C];
    static int[] w = new int[C];
    static int idx;
    static int[] dist = new int[P];
    static boolean[] st = new boolean[P];
    static final int inf = 0x3f3f3f3f;
    static ArrayList<Integer> number = new ArrayList<Integer>();//不定长数组存储n头奶牛的编号
    static void add(int x,int y,int z){
        e[idx]=y;ne[idx]=h[x];w[idx]=z;h[x]=idx++;
    }

    static int spfa(int sta){
        Arrays.fill(dist,inf);//其本质是循环给数组赋初值
        ArrayDeque<Integer> queue = new ArrayDeque<Integer>();//声明的同时也将循环队列清空了
        dist[sta]=0;
        queue.offer(sta);//queue.offer 加入队列
        st[sta]=true;
        while(!queue.isEmpty()){
            int t = queue.peek();//返回堆顶元素
            queue.pop();//删除堆顶元素,与STL不同的是它有返回值返回堆顶
            st[t] = false;
            for(int i=h[t];i!=-1;i=ne[i]){
                int j = e[i];
                if(dist[j]>dist[t]+w[i]){
                    dist[j]=dist[t]+w[i];
                    if(!st[j]){
                        queue.offer(j);
                        st[j] = true;
                    }
                }
            }
        }
        int sum=0;
        for(int i=0;i<n;i++){
            int j=number.get(i);//取出不定长数组number中下标为i的元素
            sum+=dist[j];
            if(dist[j]==inf) continue;
        }
        return sum;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); p = sc.nextInt(); c = sc.nextInt();
        for(int i=0;i<n;i++){
            int t = sc.nextInt();
            number.add(t);//加入数组
        }
        Arrays.fill(h,-1);
        for(int i=0;i<c;i++){//c条边
            int a,b,d;
            a = sc.nextInt(); b = sc.nextInt(); d = sc.nextInt();
            add(a,b,d);add(b,a,d);
        }
        int ans = inf;
        for(int i=1;i<=p;i++){
            ans = Math.min(ans,spfa(i));
        }
        System.out.println(ans);
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值