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;
}
}