OJ回溯

分配问题

分配问题
Description

对给定的n个任务与n个人之间的成本矩阵完成成本最低的任务分配策略。

Input

输入:第一行为用例个数,之后为每一个用例;用例的第一行为任务个数,即n;
用例的第二行为使用逗号隔开的人员完成任务的成本;每一个成本描述包括人员序号、任务序号和成本,使用空格隔开。人员序号和任务序号都是从1到n的整数,序号出现的次序没有固定规则。

Output

输出:每一个用例输出一行,从序号为1的人员开始,给出其分配的任务序号,使用空格隔开;使
用逗号将多个解隔开。结果按照人员分配的任务序号大小排,第一个人员的任务序号大的放在前面,如果相同则看第二个人员的任务,以此类推。

Sample Input 1

1
4
2 1 6,1 2 2,1 3 7,1 4 8,1 1 9,2 2 4,2 3 3,2 4 7,3 1 5,3 2 8,3 3 1,3 4 8,4 1 7,4 2 6,4 3 9,4 4 4
Sample Output 1

2 1 3 4

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    static Scanner scanner=new Scanner(System.in);
    static int [][] personTask;//人员任务矩阵
    static int n;//人员个数=任务个数=n
    static List<Integer> res;
    static int time;//最短时间
    static boolean[] isDistrubuted;//已经分配的任务
    public static void main(String[] args){
        int T=scanner.nextInt();
        while(T-->0){
            n=scanner.nextInt();
            scanner.nextLine();
            personTask=new int[n][n];
            res=new ArrayList<>();
            time=Integer.MAX_VALUE;
            String s[]=scanner.nextLine().split(",");
            isDistrubuted=new boolean[n];
            for(int i=0;i<s.length;i++){
                String ss[]=s[i].split(" ");
                int p=Integer.parseInt(ss[0])-1;
                int t=Integer.parseInt(ss[1])-1;
                int time=Integer.parseInt(ss[2]);
                personTask[p][t]=time;

            }
            distribute(0,0,new ArrayList<>());
            for(int i=0;i<n;i++){
                System.out.print(res.get(i));
                if(i!=n-1){
                    System.out.print(" ");
                }
            }
            System.out.println("");

        }

    }

    /**
     *
     * @param cur 递归参数  为第cur个人分配任务
     */
    static void distribute(int cur, int currentTime,List<Integer> path){
        if(cur==n) {
            if(currentTime<time){
                time=currentTime;
                res=new ArrayList<>(path);
            }
            return;
        }
        //遍历任务
        for(int i=0;i<n;i++){
            if(isDistrubuted[i]) continue;
            //分配
            isDistrubuted[i]=true;
            path.add((i+1));
            currentTime+=personTask[cur][i];
            distribute(cur+1,currentTime,path);
            //回溯
            isDistrubuted[i]=false;
            currentTime-=personTask[cur][i];
            path.remove((Integer)(i+1));

        }


    }
}

和为定值的子数组

Description

Given an array A of size N, find all combination of four elements in the array whose sum is equal to a given value K. For example, if the given array is {10, 2, 3, 4, 5, 9, 7, 8} and K = 23, one of the quadruple is “3 5 7 8” (3 + 5 + 7 + 8 = 23).

Input

The first line of input contains an integer T denoting the no of test cases. Then T test cases follow. Each test case contains two lines. The first line of input contains two integers N and K. Then in the next line are N space separated values of the array.(1<=T<=100;1<=N<=100;-1000<=K<=1000;-100<=A[]<=100)

Output

For each test case in a new line print all the quadruples present in the array separated by space which sums up to value of K. Each quadruple is unique which are separated by a delimeter “$” and are in increasing order.

Sample Input 1

2
5 3
0 0 2 1 1
7 23
10 2 3 4 5 7 8
Sample Output 1

0 0 1 2 $
2 3 8 10 $2 4 7 10 $3 5 7 8 $


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

/**
 * 求数组的子数组,且四个元素子数组满足元素和为K   并且要去掉重复的数组
 * 输入:T
 *      N  K
 *     数组元素
 * 输出 子数组 子数组之间以$分割
 *
 * Sample Input 1
 * 2
 * 5 3
 * 0 0 2 1 1
 * 7 23
 * 10 2 3 4 5 7 8
 *
 * Sample Output 1
 * 0 0 1 2 $
 * 2 3 8 10 $2 4 7 10 $3 5 7 8 $
 */
public class Main {
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int T=sc.nextInt();
        for(int t=0;t<T;t++) {
            int n = sc.nextInt();
            int k = sc.nextInt();
            int arr[] = new int[n];
            for (int i = 0; i < n; i++) {
                arr[i] = sc.nextInt();
            }
            //调用方法
            Arrays.sort(arr);//将数组进行排序
            List<List<Integer>> res = new ArrayList<List<Integer>>();
            List<Integer> l = new ArrayList<Integer>();
            int sum = 0;
            boolean[] used = new boolean[arr.length];
            getSubArrayK(res, l, k, sum, arr, used);
            for (int i = 0; i < res.size(); i++) {
                for (int j = 0; j < res.get(i).size(); j++) {
                    System.out.print(res.get(i).get(j) + " ");
                }
                System.out.print("$");

            }
            System.out.println(" ");
		}
        

    }

    private static void getSubArrayK(List<List<Integer>> list, List<Integer> l, int target, int sum, int[] candidates,boolean[] used){
        if(sum==target){
            list.add(l);
        }
        //如果元素不能到达四个元素则break
        for(int i=0;i<candidates.length;i++){
            if(l.size()+candidates.length-i<4)
                break;
            if(sum+candidates[i]>target){
                break;
            }
            if (i > 0 && candidates[i] == candidates[i - 1] && !used[i - 1]) {
                continue;
            }
            if(l.size()>0&&l.get(l.size()-1)>candidates[i]){
                continue;
            }
            if(!used[i]){
                List<Integer> newL =new ArrayList<Integer>(l);
                newL.add(candidates[i]);
                boolean[] newUsed = new boolean[used.length];
                System.arraycopy(used, 0, newUsed, 0,used.length);
                newUsed[i] = true;
                getSubArrayK(list,newL,target,sum+candidates[i],candidates, newUsed);
            }
        }
    }
}

拓扑排序的个数

import java.util.*;

/**
 * @CreateDate 20210301
 * @author zhengjiao
 * @desciption 拓扑排序的个数
 */
public class Main {
    static Scanner in=new Scanner(System.in);
    static List<Edge> edges=new ArrayList<>();
    static Set<Character> vs=new HashSet<>();//点的集合
    static Map<Character,Integer> inDegree=new LinkedHashMap<>();//点的入度。
    static int n=0;
    static int ans=0;
    static class Edge {
        char start;
        char end;

        public Edge(char start, char end) {
            this.start = start;
            this.end = end;
        }

        // 重写hashcode方法
        @Override
        public int hashCode() {
            int result = start;
            result = 17 * result + end;
            return result;
        }

        // 重写equals方法
        @Override
        public boolean equals(Object obj) {
            if(!(obj instanceof Edge)) {
                return false;
            }
            Edge edge = (Edge) obj;
            if (this == edge) {
                return true;
            }
            if (edge.start==this.start && edge.end==this.end) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public String toString() {
            return "Edge{" +
                    "start=" + start +
                    ", end=" + end +
                    '}';
        }
    }
    static void topoSort(int cnt){
        if(cnt>=n){
            ans++;
            return;
        }
        for(Map.Entry<Character,Integer> entry:inDegree.entrySet()){
            if(entry.getValue()!=0) continue;
            //取入度为0的点
            char v=entry.getKey();
            inDegree.put(v,-1);//去掉该点
            List<Character> justEdge=new ArrayList<>();//记录刚刚删除的边的集合
            for(int i=0;i<edges.size();i++){
                Edge edge=edges.get(i);
                if(edge.start==v){
                    //  入度减1
                    inDegree.put(edge.end,inDegree.get(edge.end)-1);
                    //删除边
                    justEdge.add(edge.end);
                    edges.remove(edge);
                }
            }
            topoSort(cnt+1);
            //回溯)

            inDegree.put(v,0);
            for(int i=0;i<justEdge.size();i++){
                char end=justEdge.get(i);
                //添加边
                edges.add(new Edge(v,end));
                //入度加一
                inDegree.put(end,inDegree.get(end)+1);
            }
        }

    }


    public static void main(String args[]){
        int T=in.nextInt();
        in.nextLine();
        while(T-->0){
            edges.clear();
            vs.clear();
            inDegree.clear();
            ans=0;
            n=0;
            String s[]=in.nextLine().split(",");
            for(int i=0;i<s.length;i++){
                char start=s[i].charAt(0);
                char end=s[i].charAt(2);
                edges.add(new Edge(start,end));
                inDegree.put(end,inDegree.getOrDefault(end,0)+1);
                vs.add(start);
                vs.add(end);
            }
            n=vs.size();
            for(Character v:vs){
                if(!inDegree.containsKey(v)){
                    inDegree.put(v,0);
                }
            }
           /* System.out.println(vs.toString());
            System.out.println(n);
            System.out.println(inDegree.toString());
            System.out.println(edges.toString());*/
            topoSort(0);
            System.out.println(ans);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值