ACMJava模板总结

4 篇文章 0 订阅
3 篇文章 0 订阅

1、KMP字符转匹配算法

题目描述

栗酱有一个长度为n的数列A,一个长度为m的数列B,现在询问A中有多少个长度为m的连续子序列A’, 满足(a’1+b1)%k =
(a’2+b2)%k = …… = (a’m + bm)%k。

输入描述:

第一行一个数T,表示有T组数据。
对于每组数据,
第一行三个整数,n, m, k。
第一行输入n个数, a1,a2,…,an, 表示A数列中的数,
第二行输入m个数, b1,b2,…,bm, 表示B数列中的数。

输出描述:

每一组数据输出一行,满足条件的连续子序列数量。

示例1

输入

2
3 2 5
7 8 7
8 7
3 2 5
7 8 9
8 7

输出

1
2

备注:

T≤15,
2≤m≤n≤2×105,
1≤ai,bi,k≤109
import java.io.*;

public class Main {

    private static StreamTokenizer in;
    private static PrintWriter out;
    private static int n, m, k;
    private static int arr[], S[], P[], next[];

    public static void main(String[] args) {
        in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        arr = new int[200000];
        S = new int[200000];
        P = new int[200000];
        next = new int[200000];

        int T = nextInt();
        while (T-- > 0) {
            n = nextInt();
            m = nextInt();
            k = nextInt();

            for (int i = 0; i < n; i++) arr[i] = nextInt();
            for (int i = 0; i < n - 1; ++i) P[i] = ((arr[i] - arr[i + 1]) % k + k) % k;
            for (int i = 0; i < m; i++) arr[i] = nextInt();
            for (int i = 0; i < m - 1; ++i) S[i] = ((arr[i] - arr[i + 1]) % k + k) % k;
            if (T == 0)
                out.print(kmp(P, S));
            else
                out.println(kmp(P, S));
            out.flush();
        }
    }

    private static int kmp(int P[], int S[]) {
        int ans = 0;
        getNext(S);
        int i = 0, j = 0;
        int len_p = n - 1, len_s = m - 1;
        while (i < len_p && j < len_s) {
            if (j == -1 || (P[i] + S[j]) % k == 0) {
                ++i;
                ++j;
            } else j = next[j];
            if (j == len_s) {
                ans++;
                j = next[j];
            }
        }
        return ans;
    }

    private static void getNext(int arr[]) {
        int suffix = 0, prefix = -1, len = m - 1;
        next[0] = -1;
        while (suffix < len) {
            if (prefix == -1 || arr[prefix] == arr[suffix]) {
                next[++suffix] = ++prefix;
            } else prefix = next[prefix];
        }
    }

    private static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int) in.nval;
    }


}

题目描述

有一个字符串 让你找到这个字符串 S 里面的子串T 这个子串 T 必须满足即使这个串的前缀 也是这个 串的后缀 并且
在字符串中也出现过一次的(提示 要求满足前后缀的同时也要在字符串中出现一次 只是前后缀可不行 输出最长满足要求字符串)

输入描述:

给出一个字符串 长度 1 到 1e6  全部是小写字母

输出描述:

如果找的到就输出这个子串T 如果不行就输出 Just a legend

示例1

输入

fixprefixsuffix

输出

fix

示例2

输入

abcdabc

输出

Just a legend
import java.util.Scanner;
/**
 * 字符串的问题
 *
 * @author Birenyin on 2021-09-10
 * @version 1.8
 * @since1.5
 */
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        String res = solveProblem(s); 
        System.out.print(res);
    }
    public static String solveProblem(String mother){
        int[] next = getNext(mother);
        StringBuilder maxPre = new StringBuilder(mother.substring(0,next[mother.length()] )); //最长前后缀
        if(maxPre.length() == 0) return "Just a legend";
        for(int i = 0; ; i++){
            boolean matchRes = match(1, mother.length() - 2, mother, maxPre.toString(), next);
            if(matchRes) return maxPre.toString();
            int start =  next[maxPre.length()] ;
            int end = maxPre.length() ;
            if (start <= 0 || start >= end) break;
            maxPre.replace(start,end,"");
        }
        return "Just a legend";
    }
    //得到next数组
    public static int[] getNext(String mother){
            int [] next = new int[mother.length()+1];//next数组记录当前字符前的字符串最大公共前后缀

            int i = 0,k = -1;
            next[i] = k;
            while( i < mother.length()){
                if(k == -1 || mother.charAt(i) == mother.charAt(k)){
                    i++;
                    k++;
                    next[i] = k;
                }else
                    k = next[k];
            }
            return next;
    }
    //指定母串的start和end来进行匹配
    public static boolean match(int start,int end,String mother,String son, int[] next){

        int i = start;
        int j = 0;
        while(i <= end && j < son.length()){
            if( j == -1 || mother.charAt(i) == son.charAt(j)){
                i++;
                j++;
            }else
                j = next[j];
        }
        if(j == son.length()) return true;
        return false ;
    }
}

2、动态规划

题目描述

美团旅行团队最近打算推出一项新服务,为景区的各个景点规划游览路线,提升游客满意度。其中一个重要的问题是对于一个景区道路网,求出游客的满意度的期望值。基于用户的喜好差异,我们需要对男性游客和女性游客的满意度分别计算。
景区被描述成一张n个点、m条边的无向图(无重边,无自环)。每个点代表一个景点,第i个景点游览需要耗费ci分钟,会让男性游客和女性游客的满意度分别增加h1i和h2i(满意度初始值都为0)。每条边代表一条路,第i条边连接编号为xi,yi的两个景点,从景点xi走到yi和从yi走到xi的时间都是ti分钟。
每个游客在景区中最长可以游览k分钟,最开始会随机的通过不同大门进入到一个景点开始游览,每游览完一个项目,游客会等概率随机选择一个可以从当前景点直达且来得及游览的景点作为下一个游览目标(已经游览过的景点也会因为有各种新活动而让游客再次考虑,所以我们这里不区分景点是否已经游览过)。如果游览完一个景点后,周围没有来得及游览的景点,本次游玩就结束了。
请你分别计算小y和妹子在游玩结束后开心度的期望。

输入描述:

第一行给出三个空格隔开的整数,分别表示n, m, k(0 < n ≤ 100, 1 * 60 ≤ k ≤ 8 * 60)
接下来的n行,每行三个空格隔开的整数,分别表示ci, h1i, h2i (10 ≤ ci ≤ 60,0 < h1i, h2i ≤ 100)
接下来的m行,每行三个空格隔开的整数,分别表示xi, yi, ti (0 < ti ≤ 15)

输出描述:

两个用空格隔开的实数,分表表示小y和妹子开心度的期望,精确到小数点后5位。

示例1

输入

5 4 60
25 12 83
30 38 90
16 13 70
22 15 63
50 72 18
2 1 7
3 1 7
4 3 1
5 3 10

输出

39.20000 114.40000
import java.util.*;

public class Main{
    
    
    private static int[] c;
    private static int[] h1;
    private static int[] h2;
    private static LinkedList<Pair>[] g;
    
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int k = sc.nextInt();
        
        c = new int[n+1];
        h1 = new int[n+1];
        h2 = new int[n+1];
        g = new LinkedList[n+1];
        for(int i=1;i<=n;i++){
            g[i] = new LinkedList<>();
        }
        for(int i=1;i<=n;i++){
            c[i] = sc.nextInt();
            h1[i] = sc.nextInt();
            h2[i] = sc.nextInt();
        }
        for(int i=0;i<m;i++){
            int x = sc.nextInt();
            int y = sc.nextInt();
            int t = sc.nextInt();
            g[x].add(new Pair(y,t));
            g[y].add(new Pair(x,t));
        }
        
        
        System.out.printf("%.5f %.5f",calc(n,m,k,h1),calc(n,m,k,h2));
    }
    
    
    private static double calc(int n,int m,int k,int[] h){
        double[][] f = new double[k+1][n+1];
        double res = 0;
        for(int i=1;i<=n;i++){
            f[c[i]][i] = 1.0/n;
        }
        for(int t=0;t<=k;t++){
            for(int cur=1;cur<=n;cur++) res += f[t][cur] * h[cur];
            for(int cur=1;cur<=n;cur++){
                int num = 0;
                for(Pair p : g[cur]){
                    if((k-t) >= (p.time+c[p.dest])) num++;
                }
                if(num==0) continue;
                for(Pair p : g[cur]){
                    if((k-t) >= (p.time+c[p.dest])){
                        f[t+p.time+c[p.dest]][p.dest] += f[t][cur]/num;
                    }
                }
            }
        }
        return res;
    }
}

class Pair{
    
    public int dest;
    public int time;
    public Pair(int dest,int time){
        this.dest = dest;
        this.time = time;
    }
    
}

3、快速排序

题目描述

萌萌哒栗酱有n个点,第i个点有点权ai(ai为偶数),你可以在任意两点之间添加一条边,每一条边的边权为连接它的两个点的点权之和除以2。
现在她需要添加n-1条边,使任意两点相互连通,并且连通后的边权和最大。

输入描述:

第一行一个数T,表示有T组数据。
对于每组数据,第一行输入一个数n,表示点的数量,
接下来一行输入n个数,a1,a2,…,an,其中ai表示第i个点的点权。
任意两个相邻数之间用空格隔开。

输出描述:

对于每一组数据,输出一个数,即最大边权和。

示例1

输入

2
5
4 2 4 4 2
10
10 2 6 4 6 8 10 8 2 10

输出

14
73

备注:

T≤10
1≤n≤103
1≤ai≤103,保证ai为偶数。
import java.util.*;
public class Main{
    public static void main(String args[]){
     Scanner sc=new Scanner(System.in);
     int n=sc.nextInt();
        while(n--!=0){
            int k=sc.nextInt();int a[]=new int[k];
            for(int i=0;i<k;i++)a[i]=sc.nextInt();
           Arrays.sort(a);
            int sum=0;
            for(int i=0;i<k-1;i++) sum+=a[k-1]+a[i]>>1;
            System.out.println(sum);
        }
    }
   
}

4、背包dp

题目描述

又是一年省赛,喆神收拾各种算法书要去打比赛了,但他最多只能背两个背包,而算法书分散在好几个背包里(zhe神有钱),他想知道,最后是否能够把所有的书都放在两个背包里。

输入描述:

第一行一个数n,表示背包的数量。(0 <= n <=100)
第二行n个数ai,分别表示每个背包里的书的个数。(0 <= ai <= 10000)
第三行n个数bi,分别表示每个背包的背包容量。(0 <= bi <= 10000)

输出描述:

如果可以把所有的书放在两个背包里,输出“YES”(没有引号)
否则,输出“NO”

示例1

输入

2
3 5
3 6

输出

YES
import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] a=new int[n];
        int sum=0,k=0;
        for(int i=0;i<n;i++) {sum+=sc.nextInt();}
        for(int i=0;i<n;i++) a[i]=sc.nextInt();
        Arrays.sort(a);
        
         if(n==1&&sum<=a[0]){System.out.print("YES");}
        else if(n>=2&&sum<=a[n-1]+a[n-2]){System.out.print("YES");}
        else{System.out.print("NO");}
    }
}

5、并查集

题目描述

给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:

若x在集合A中,则a-x必须也在集合A中。

若x在集合B中,则b-x必须也在集合B中。

输入描述:

第一行 三个数 n a b  1<=n<=1e5  1<=a,b<=1e9
第二行 n个数 p1 p2 p3...pn 1<=pi<=1e9

输出描述:

如果可以恰好分开就输出第一行 YES
然后第二行输出 n个数 分别代表pi 是哪个集合的  0 代表是A集合 1代表是B 集合
不行就输出NO
放在哪个集合都可以的时候优先放B

示例1

输入

4 5 9
2 3 4 5

输出

YES
0 0 1 1

示例2

输入

3 3 4
1 2 4

输出

NO
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.HashMap;
import java.util.Map;
/*
    出错误的地方:
                离散化从1 - n   0  和 n + 1  为其他的数组、、
                并查集的合并操作和查找父节点的操作都是正确的、、
                HashMap   判断键是否有对应的值、 应该 get 后判断是否为空、、
*/
public class Main {
    static final int MAXN = 100005; 
    static int num [] = new int [MAXN]; // 存的是输入的数据、、、 
    static int fa [] = new int[MAXN];   // 并查集、、
    static Map<Integer, Integer> mp = new HashMap<>();
    
    static int n, a, b;
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        
        in.nextToken(); n = (int)in.nval; //   n  个输入的数、
        in.nextToken(); a = (int)in.nval;  // 存输入的 a
        in.nextToken(); b = (int)in.nval; // 存输入的 b
        
        int max = -1; //  用来找最大的数 、、、
        for(int i = 1; i <= n; i++){
            in.nextToken(); num[i] = (int)in.nval;
            mp.put(num[i], i);   //    存进 HashMap 中、、    这个应该用到了离散化、、 (压缩起来)
            max = Math.max(max, num[i]);  
        }
        if(max > Math.max(a, b)){   // 如果最大的数 都比这个大的话、 那当然不行咯、、
            out.println("NO");
//            out.println("max = " + max + " 是这里输出的呢、标记为 1  、、");
        }else{  //  那么 来看看是否可行吧、、
            for(int i = 0; i <= n + 1; i++){
                fa[i] = i;  //  每个人 离散化的值都指向自己、、
            }
            for(int i = 1; i <= n; i++){
                if(mp.get(a - num[i]) != null){ // 这 HashMap 里面有数啊、  那就合并起来啊、、
//                    Union(i, mp.get(a - num[i]));
                    Union(mp.get(a - num[i]), i);
                }else{
                    Union(i, n + 1); //  没有 扔另一个里面 n + 1(优先扔 b)
                }
                
                if(mp.get(b - num[i]) != null){
//                    Union(i, mp.get(b - num[i]));  
                    Union(mp.get(b - num[i]), i);
                }else{
                    Union(i, 0);  //  0  也算是另一个数组、、(b 扔不了,就扔另一个吧)
                }
            }
            
            int A = Find(0); int B = Find(n + 1); // 这两个 的是否是一个集合里面的、
            if(A != B){  // 不是 那就好 、、、
                out.println("YES");   
                for(int i = 1; i <= n; i++){
                    if(i != 1) out.print(" ");
                    if(Find(i) == A) out.print(0);
                    else out.print("1");
                }
                out.println();
            }else{
                out.println("NO");
//                out.println("A = " + A + " B = " + B  + " 是这里输出的呢、标记为 2  、、");
            }
        }
        out.flush();
        
    }
    
    
    static int Find(int x) {
//        return fa[x] == x ? x :x = Find(fa[x]);  // 这个是没有使用路径压缩的、  下面的那个是使用了路径压缩的、、
        int r = x, t;
        while(r != fa[r]) {
            r = fa[r];
        }
        while(x != r) {
            t = fa[x];
            fa[x] = r;
            x = t;
        }
        return r;
    }
    static void Union(int x, int y) {
        x = Find(x);
        y = Find(y);
        if(x != y) {
            fa[x] = y;
        }
    }
    

    
}

6、AC自动机

题目描述

某人读论文,一篇论文是由许多单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。

输入描述:

第一个一个整数N,表示有多少个单词,接下来N行每行一个单词。每个单词由小写字母组成,N ≤ 200,单词长度不超过10^6

输出描述:

输出N个整数,第i行的数字表示第i个单词在文章中出现了多少次。

示例1

输入

3
a
aa
aaa

输出

6
3
1

备注:

30%的数据, 单词总长度不超过 10310^3103。
100%的数据,1≤n≤2001 \leq n \leq 2001≤n≤200,单词总长度不超过 10610^6106。
import java.util.Scanner;

public class Main
{

	public static int count;
	public static void main(String[] args)
	{
		Scanner sc=new Scanner(System.in);
		while(sc.hasNext())
		{
			int n=sc.nextInt();
			String[]c=new String[n];
			StringBuilder sb=new StringBuilder();
			for(int i=0;i<n;i++)
			{
				c[i]=sc.next();
				sb.append(c[i]+" ");
			}
			for(int i=0;i<c.length;i++)
			{
				count=0;
				for(int j=0;j<c.length;j++)
				{
					char[]a=c[i].toCharArray();
					char[]b=c[j].toCharArray();
					count+=StringCounnt(a,b);
				}
				System.out.println(count);
			}
		}
	}
	
	public static int StringCounnt(char[]a,char[]b)
	{
		count=0;
		for(int i=0;i<=b.length-a.length;i++)
		{
			boolean t=true;
			int j=0;
			while(true)
			{
				if(a[j]!=b[j+i])
				{
					t=false;
					break;
				}
				j++;
				if(j==a.length)break;
			}
			if(t==true)count++;
		}
		return count;
	}

}


import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class Main {
    static InputReader in = new InputReader();
    //static QuickReader in = new QuickReader(new BufferedReader(new InputStreamReader(System.in)));
    public static void main(String[] args) throws IOException {
        solveProblem();
    }

    public static void solveProblem() throws IOException {
        int num = in.nextInt();  //单词个数
        List<String> list = new ArrayList<>(); //保存输入的单词

        for(int i = 0; i < num; i++) {
            String s = in.next();
            list.add(s);
            insert(s);       //初始化前缀树
        }
        getFail();//初始化fail数组
        list.forEach(e -> query(e));//查询
        getResult();

        //打印结果
        list.forEach(e ->{ System.out.println(resArray[map.get(e)]); });

    }

    public static void getResult(){
        Set<Integer> set = resMap.keySet();
        Iterator it = set.iterator();

        while(it.hasNext()){
            int index = (Integer)it.next();
            ArrayList<Integer> list = resMap.get(index);
            list.forEach(e -> resArray[e] += cnt[index] );
        }
    }



    static int size = (int)1e6+5;
    static int k = 1; //记录创建的是第几个结点
    static int[][] trie = new int[size][26]; //前缀树
    static int[] codeCnt = new int[size];    //记录终结结点
    static int[] fail = new int[size];  //记录回查结点
    static Map<String,Integer> map = new HashMap<>();
    static int[] resArray = new int[size]; //记录结果的数组

    //将目标字符串插入
    public static void insert(String s){
        int p = 0;
        int c = 0;
        //使用单词构建字典树
        for(int i = 0; i < s.length(); i++){
            c = s.charAt(i) - 'a';
            if(trie[p][c] == 0){ trie[p][c] = k;k++; }
            p = trie[p][c];
        }
        codeCnt[p]++; //记录终结结点
        map.put(s,p); //记录单词末尾对应的结点编号
    }
    //获取fail数组
    public static void getFail(){
        Queue<Integer> queue = new LinkedList<>();
        for(int i = 0; i < 26; i++)
            if(trie[0][i] != 0) queue.add(trie[0][i]); //将第二层所有出现了的字母扔进队列
        while(!queue.isEmpty()) {
            int now = queue.remove();//移除头部元素,并返回该元素
            for(int i = 0; i < 26; i++){
                if(trie[now][i] != 0){
                    //如果有这个子节点为字母i+'a',则让这个节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
                    fail[trie[now][i]] = trie[fail[now]][i];
                    queue.add(trie[now][i]);
                }else
                    //否则就让当前节点的这个子节点,指向当前节点fail指针的这个子节点
                  trie[now][i] = trie[fail[now]][i];
            }
        }
    }

    static HashMap<Integer,ArrayList<Integer>> resMap = new HashMap<>(); //记录终结结点跳转过程中会经过的终结结点
    static int []cnt = new int[size]; //记录
    //查询每个单词,记录在查询过程中找到的单词次数
    public static void query(String s){
        int now = 0;

        for(int i = 0; i < s.length(); i++){
            now = trie[now][s.charAt(i)- 'a'];

            int flag = 0;
            List<Integer> list = resMap.get(now);
            if(list != null){ cnt[now]++; continue; }
            ArrayList<Integer> newList = new ArrayList<>();
            resMap.put(now,newList);

            for(int j = now; j != 0; j = fail[j])
                if(codeCnt[j] != 0) {
                    newList.add(j);
                    flag = 1;
                }
            if(flag == 1) cnt[now]++;
            //    if(codeCnt[j] != 0) resArray[j]++;
        }
    }
}
//加速读取和写入
class InputReader {
    BufferedReader buf;
    StringTokenizer tok;
    InputReader() {
        buf = new BufferedReader(new InputStreamReader(System.in));
    }
    boolean hasNext() {
        while (tok == null || !tok.hasMoreElements()) {
            try {
                tok = new StringTokenizer(buf.readLine());
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }
    String next() {
        if (hasNext())
            return tok.nextToken();
        return null;
    }
    int nextInt() {
        return Integer.parseInt(next());
    }
    long nextLong() {
        return Long.parseLong(next());
    }
    double nextDouble() {
        return Double.parseDouble(next());
    }
    BigInteger nextBigInteger() {
        return new BigInteger(next());
    }
    BigDecimal nextBigDecimal() {
        return new BigDecimal(next());
    }
}

class QuickReader extends StreamTokenizer {
    public QuickReader(Reader arg0) {
        super(arg0);
    }
    public int nextInt() throws IOException {
        this.nextToken();
        return (int)Math.round(this.nval);
    }
    public String next() throws IOException{
        this.nextToken();
        return this.sval;
    }
}

7、最短路

简单暴力的题目要求:

给定一个有n个顶点(从1到n编号),m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路。

输入描述:

第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。

输出描述:

共n-1行,第i行表示1号点到i+1号点的最短路。

示例1

输入

3 3
1 2 -1
2 3 -1
3 1 2

输出

-1
-2

说明

对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
import java.util.*;

public class Main{
	public static int[] e = new int[200010];
	public static int[] w = new int[200010];
	public static int[] ne = new int[200010];
	public static int[] h = new int[200010];
	public static int tot = 0;
	
	public static int n, m;
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		m = in.nextInt();
		
		for (int  i  = 0; i < m; i ++ )
			add(in.nextInt(), in.nextInt(), in.nextInt());
		
		int[] dist = new int[n  + 1];
		boolean[] st = new boolean[n + 1];
		Arrays.fill(dist, Integer.MAX_VALUE);
		dist[1] = 0;
		
		Queue<Integer>q = new LinkedList<Integer>();
		q.offer(1);
		while (!q.isEmpty())
		{
			int x = q.peek();
			q.poll();
			st[x] = true;
//			System.out.println(x + "  " + h[x]);
			for (int i = h[x]; i > 0; i = ne[i])
			{
//				System.out.println(x + "   " + e[i] + " " + w[i]);
				int y = e[i], z = w[i];
				if (dist[y] > dist[x] + z)
				{
					dist[y] = dist[x] + z;
					if (!st[y]) 
					{
						q.offer(y);
						st[y] = true;
					}
				}
			}
		}
		for (int i = 2; i <= n; i ++ ) 
			System.out.println(dist[i]);
	}
	
	public static void add(int a,  int b, int c)
	{
		e[++ tot] = b;
		w[tot] = c;
		ne[tot] = h[a];
		h[a] = tot;
	}
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    // IO模板
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StreamTokenizer st = new StreamTokenizer(br);

    private long readLong() throws IOException {
        st.nextToken();
        return (long) st.nval;
    }

    private int readInt() throws IOException {
        st.nextToken();
        return (int) st.nval;
    }

    private String readString() throws Exception {
        st.nextToken();
        return st.sval;
    }

    public static void main(String[] args) throws IOException {
        new Main().run();
    }

    // 算法开始
    final int N = (int) 1e5 + 10;
    int n, m;

    private class Edge {
        int to, next, dis;
    }

    Edge[] edges = new Edge[N << 1];
    int[] head = new int[N], dist = new int[N];
    int idx = 1;
    boolean[] vis = new boolean[N];

    private void run() throws IOException {
        n = readInt();
        m = readInt();
        Arrays.fill(head, -1);
        for (int i = 0; i < edges.length; i++) {
            edges[i] = new Edge();
        }

        for (int i = 0; i < m; i++) {
            int u = readInt(), v = readInt(), w = readInt();
            addEdge(u, v, w);
        }

        spfa();

        for (int i = 2; i <= n; i++)
            System.out.println(dist[i]);
    }

    private void spfa() {
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[1] = 0;
        Queue<Integer> q = new LinkedList<>();
        q.offer(1);
        vis[1] = true;

        while (!q.isEmpty()) {
            int t = q.poll();
            for (int i = head[t]; i != -1; i = edges[i].next) {
                int j = edges[i].to;
                if (dist[j] > dist[t] + edges[i].dis) {
                    dist[j] = dist[t] + edges[i].dis;
                    if (!vis[j]) {
                        q.offer(j);
                        vis[j] = true;
                    }
                }
            }
        }
    }

    private void addEdge(int u, int v, int w) {
        edges[idx].to = v;
        edges[idx].next = head[u];
        edges[idx].dis = w;
        head[u] = idx++;
    }
}

8、最小生成树

胡队长带领HA实验的战士们玩真人CS,真人CS的地图由一些据点组成,现在胡队长已经占领了n个据点,为了方便,将他们编号为1-n,为了隐蔽,胡队长命令战士们在每个据点出挖一个坑,让战士们躲在坑里。由于需要在任意两个点之间传递信息,两个坑之间必须挖出至少一条通路,而挖沟是一件很麻烦的差事,所以胡队长希望挖出数量尽可能少的沟,使得任意两个据点之间有至少一条通路,顺便,尽可能的∑d[i][j]使最小(其中d[i][j]为据点i到j的距离)。

输入描述:

第一行有2个正整数n,m,m表示可供挖的沟数。
接下来m行,每行3个数a,b,v,每行描述一条可供挖的沟,该沟可以使a与b连通,长度为v。

输出描述:

输出一行,一个正整数,表示要使得任意两个据点之间有一条通路,至少需要挖长的沟。(数据保证有解)

示例1

输入

2 2
1 2 1
1 2 3

输出

1

示例2

输入

3 3
1 2 3
2 3 4
1 3 5

输出

7

备注:

对于100%的测试数据:
1 ≤ n ≤ 100000
1 ≤ m ≤ 500000
1 ≤ v ≤ 10000
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.time.Year;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;

import javax.security.auth.x500.X500Principal;
 
public class Main 
{
	static int[] f;
    public static void main(String[] args) throws IOException 
    {
    	int n = ini();
    	f = new int[n+1];
    	int m = ini();
        for(int i=0;i<=n;i++) {
       		f[i] = i;
       	}
       	PriorityQueue<jpg> pp = new PriorityQueue<jpg>(new Comparator<jpg>()
		{
       		public int compare(jpg o1,jpg o2)
       		{
       			return o1.c-o2.c;
       		}
		});
       	for(int i=0;i<m;i++) 
       	{
       		pp.add(new jpg(ini(),ini(),ini()));
       	}
       	int ans = 0;
       	int ans1 = 0;
        while(!pp.isEmpty()) 
       	{
       		jpg o = pp.poll();
       		if(zbb(o.a)!=zbb(o.b))
       		{
       			merge(o.a, o.b);
       			ans+=o.c;
       			ans1++;
       		}
       		if(ans1 == m-1)break;
       	}
       	System.out.println(ans);
    }
    static int zbb(int x)
    {
    	return f[x]==x ? x : (f[x] = zbb(f[x]));
    }
    static void merge(int a,int b)
    {
    	a = zbb(a);
    	b = zbb(b);
    	f[a] = b;
    }
    static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static int ini() throws IOException
    {
        in.nextToken();
        return (int)in.nval;
    }
    static double ind() throws IOException
    {
        in.nextToken();
        return in.nval;
    }
    static String ins() throws IOException
    {
        in.nextToken();
        return in.sval;
    }
    static long inl() throws IOException
    {
        in.nextToken();
        return (long)in.nval;
    }
}
class jpg{
	int a,b,c;
	public jpg(int a,int b,int c)
	{
		this.a = a;
		this.b = b;
		this.c = c;
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;

public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);
    static int N = 100010, M = 500010, n, m;
    static int p[] = new int[N];
    static tt[] e = new tt[M];

    public static void main(String[] args) throws IOException
    {
        String s[] = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        for (int i = 0; i < m; i++) {
            s = br.readLine().split(" ");
            int a = Integer.parseInt(s[0]);
            int b = Integer.parseInt(s[1]);
            int w = Integer.parseInt(s[2]);
            e[i] = new tt(a, b, w);
        }

        Arrays.sort(e, 0, m);

        for (int i = 1; i <= n; i++) p[i] = i;

        int res = 0, cnt = 0;
        for (int i = 0; i < m; i++) {
            int a = e[i].a;
            int b = e[i].b;
            int c = e[i].c;
            int x = find(a);
            int y = find(b);
            if (x != y) {
                p[x] = y;
                res += c;
                cnt++;
            }
        }
        if (cnt < n - 1) pw.println("impossible");
        else pw.println(res);
        pw.flush();
        pw.close();
        br.close();
    }

    public static int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

}

class tt implements Comparable<tt> {
    int a, b, c;

    public tt(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public int compareTo(tt o) {
        return this.c - o.c;
    }
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    static InputReader in = new InputReader();

    static int[] fa;

    static int find(int x) {
        return fa[x] == x ? x : (fa[x] = find(fa[x]));
    }

    static void merge(int x, int y) {
        x = find(x);
        y = find(y);
        fa[x] = y;
    }

    public static void main(String[] args) {
        while (in.hasNext()) {
            int n = in.nextInt(), m = in.nextInt(), cnt = 0;
            fa = new int[n + 1];
            long sum = 0;
            for (int i = 0; i <= n; i++) {
                fa[i] = i;
            }
            PriorityQueue<M> que = new PriorityQueue<M>(new Comparator<M>() {

                @Override
                public int compare(M o1, M o2) {
                    // TODO Auto-generated method stub
                    return o1.v - o2.v;
                }
            });
            for (int i = 0; i < m; i++) {
                que.add(new M(in.nextInt(), in.nextInt(), in.nextInt()));
            }
            while (!que.isEmpty()) {
                M mm = que.poll();
                if (find(mm.x) != find(mm.y)) {
                    merge(mm.x, mm.y);
                    sum += mm.v;
                    cnt++;
                }
                if (cnt == m - 1)
                    break;
            }
            System.out.println(sum);
        }
        out.flush();
    }

}

class M {
    int x, y, v;

    public M(int x, int y, int v) {
        this.x = x;
        this.y = y;
        this.v = v;
    }

}

class InputReader {
    BufferedReader buf;

    StringTokenizer tok;

    InputReader() {
        buf = new BufferedReader(new InputStreamReader(System.in));
    }

    boolean hasNext() {
        while (tok == null || !tok.hasMoreElements()) {
            try {
                tok = new StringTokenizer(buf.readLine());
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }

    String next() {
        if (hasNext())
            return tok.nextToken();
        return null;
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }

    BigInteger nextBigInteger() {
        return new BigInteger(next());
    }

    BigDecimal nextBigDecimal() {
        return new BigDecimal(next());
    }
}

9、贪心算法

牛牛有最多50个物品,每个物品有一个type标号,并且有一个taste值,现在要求选择若干个物品放进背包使得x *
y最大,x为选择的不同type的数量,y为总的taste值之和

输入描述:

第一行输入一个整数n表示物品的数量(1 ≤ n ≤ 50)

第二行输入 n个整数typei表示每个物品的类型(1 ≤ typei ≤ 100)

第三行输入n个整数tastei(-100000 ≤ tastei ≤ 100000)

输出描述:

输出一个整数

示例1

输入

2
1 2
4 7

输出

22

示例2

输入

2
1 1
-1 -1

输出

0

示例3

输入

3
1 2 3
7 4 -1

输出

30

备注:

子任务一30分:n,m<=10

子任务二30分:n,m<=20

子任务三40分:n,m<=50
 import java.io.*;
import java.util.Arrays;

public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static BufferedReader inline=new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out=new PrintWriter(System.out);
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		in.nextToken();
		int n=(int)in.nval;
		 
		int[] a=new int[n];
		int[] b=new int[n];
		int[] c=new int[105];
		for(int i=0;i<n;i++)
		{
			in.nextToken();
			a[i]=(int)in.nval;
			
		}
		for(int i=0;i<n;i++)
		{
			in.nextToken();
			b[i]=(int)in.nval;
		}
		//Arrays.sort(b);
		for(int i=0;i<n;i++)
		{
			for(int j=i+1;j<n;j++)
			{
				if(b[i]>b[j])
				{
					int t=b[i];
					b[i]=b[j];
					b[j]=t;
					t=a[i];
					a[i]=a[j];
					a[j]=t;
				}
			}
		}
		int count=0;
		int sum=0;
		int wei=-1;
		for(int i=n-1;i>=0;i--)
		{
			 if(c[a[i]]==0)
			 {
				 if(sum*count<=(sum+b[i])*(count+1))
				 {
					 sum=sum+b[i];
					 c[a[i]]=1;
					 count++;
				 }
			 }
			 else
			 {
				 if(b[i]>=0)
					 sum=sum+b[i];
			 }
		}
		  
		out.println(sum*count);
		out.flush();
	}
}

10、位运算

题目描述

托米完成了1317的上一个任务,十分高兴,可是考验还没有结束 说话间1317给了托米 n 个自然数 a1… an,
托米可以选出一些带回家,但是他选出的数需要满足一些条件 设托米选出来了k 个数 b1,b2… bk, 设这个数列 b 的给值为 b
中所有数按位与的结果,如果你能找到一个整除 b 的最大的 2的v次方,(v≥ 0), 则设定 v 为这个数列的给价,如果不存在这样的
v,则给价值为 -1, 1317 希望托米在最大化给价的情况下,最大化 k

输入描述:

第一行输入一个整数 n, 第二行输入 a1...an

输出描述:

第一行输出最大的整数 k, 第二行输出 k 个整数 b1... bk, 按原数列的相对顺序输出 (如果行末有额外空格可能会格式错误)

示例1

输入

5
1 2 3 4 5

输出

2
4 5

备注:

n≤ 105, a1... an < 231
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
	public static void main(String[] arge) {	
		Scanner sc=new Scanner(System.in);
		List <Integer>list=new ArrayList<Integer>();
		List <Integer> total = new ArrayList<Integer>();
		int n =sc.nextInt();
		for(int i=0;i<n;i++)
		{
			list.add(sc.nextInt());
		}
		for(int i=30;i>=0;i--)
		{	
			int k=1<<i;//设置一个2的k次方
			int x=(1<<i)-1;//使位数减一,且每个位置变成一,例如2的3次方为1000,x为0111。
			for(int j=0;j<list.size();j++)
			{
				if((k&list.get(j))!=0) //匹配相同位数
				{	
					total.add(list.get(j));
					x=x&list.get(j);//对除首位的位置进行位运算
				}
			}
			if(x!=0)//若结束,除首位之外还有位置为1,例如10100,不为2的n次方,则进入下个循环。
			total.clear();
			else//找到了,相同位数的数的位运算&,除首位外,全为0。
			{
				System.out.println(total.size());
				for(int j=0;j<total.size();j++)
				{
					System.out.print(total.get(j)+" ");
				}
				break;
			}
		}
		
}

}

11、哈希表

求众数

//哈希表1
class Solution {
    public List<Integer> majorityElement(int[] nums) {
        HashMap<Integer, Integer> cnt = new HashMap<Integer, Integer>();

        for (int i = 0; i < nums.length; i++) {
            if (cnt.containsKey(nums[i])) {
                cnt.put(nums[i], cnt.get(nums[i]) + 1);
            } else {
                cnt.put(nums[i], 1);
            }
        }
        List<Integer> ans = new ArrayList<>();
        for (int x : cnt.keySet()) {
            if (cnt.get(x) > nums.length / 3) {
                ans.add(x);
            }
        }
   
        return ans;
    }
}
//哈希表2
class Solution {
    private Map<Integer, Integer> countNums(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            if (!counts.containsKey(num)) {
                counts.put(num, 1);
            } else {
                counts.put(num, counts.get(num) + 1);
            }
        }
        return counts;
    }

    public List<Integer> majorityElement(int[] nums) {
        Map<Integer, Integer> counts = countNums(nums);
        List<Integer> list = new ArrayList<>();
        Map.Entry<Integer, Integer> majorityEntry = null;
        for (Map.Entry<Integer, Integer> entry : counts.entrySet()) {
            if (entry.getValue() > ((nums.length)/3)) {
                majorityEntry = entry;
                list.add(majorityEntry.getKey());
                majorityEntry = null;
            }
        }

        return list;
         
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
上海交通大学ACM模板是指为了方便上海交通大学ACM队伍在参加ACM国内外比赛时,准备的一份包含常用算法模板和数据结构实现的文件。这份模板ACM队伍日常训练和比赛中必备的工具和参考资料。 ACM模板通常包括多个文件,每个文件对应一个具体的算法或数据结构,并提供了相应算法的思想、伪代码和具体实现。常见的内容包括但不限于:搜索算法、图论算法动态规划、字符串处理、数论算法、几何算法、数据结构等。 ACM模板的好处主要有以下几点: 1. 提高编程效率:ACM模板中的算法和数据结构已经经过了优化和测试,可以直接拿来使用,避免了从零开始编写代码的时间和精力消耗。 2. 加深理解:通过研究ACM模板中的算法和数据结构实现,可以更深入地了解算法的原理和应用场景,从而提升对ACM竞赛中常见问题的解决能力。 3. 快速调试:ACM比赛通常时间紧迫,要求快速解决问题。ACM模板可以提供一些已经调试通过的代码,可以直接用于ACM比赛中,减少调试的时间。 4. 统一编程习惯:ACM模板中的代码通常是经过一段时间的磨合和调试得到的,可以作为一个学习的范本,帮助学习者养成良好的编程习惯。 上海交通大学ACM模板是上海交通大学ACM队伍根据自身经验和成果整理而成的,旨在为队员提供便利和帮助。同时,ACM模板也可以随着时间的推移进行更新和完善,以适应新的算法和数据结构的发展和变化。 总的来说,上海交通大学ACM模板ACM竞赛中的宝贵资料,对于提升队伍的竞赛实力和解决问题的效率具有重要意义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值