提交 c1210e3c 编写于 作者: qq_36480062's avatar qq_36480062

c

上级 89c4564f
......@@ -54,7 +54,7 @@ public class Tarjan求LCA {
}
for (int i = 0; i < m; i++) {
addq(nextInt(), nextInt(), i);
}
}//存储询问
tarjan(root, 0);
for (int i = 0; i < m; i++) {
bw.write(result[i] + "\n");
......
......@@ -5,6 +5,13 @@ import java.util.Scanner;
/**
* https://blog.csdn.net/qq_30277239/article/details/100881221
* 3
* aba
* 5
* ababa
* out:
* 0
* 2
*/
public class KMP {
public static void main(String[] args) {
......@@ -46,13 +53,4 @@ public class KMP {
}
}
static void it() {
ne[0] = -1;
int t = 0;
for (int i = 1; i <= n; i++) {
t = ne[i - 1];
while (t != -1 && p[i - 1] != p[t]) t = ne[t];
ne[i] = t + 1;
}
}
}
......@@ -7,11 +7,42 @@ import java.util.StringTokenizer;
import static java.lang.System.in;
/**
* 烽火台是重要的军事防御设施,一般建在交通要道或险要处。
* 一旦有军情发生,则白天用浓烟,晚上有火光传递军情。
* 在某两个城市之间有 n 座烽火台,每个烽火台发出信号都有一定的代价。
* 为了使情报准确传递,在连续 m 个烽火台中至少要有一个发出信号。
* 现在输入 n,m和每个烽火台的代价,请计算在两城市之间准确传递情报所需花费的总代价最少为多少。
* 输入格式
* 第一行是两个整数 n,m,具体含义见题目描述;
* 第二行 n 个整数表示每个烽火台的代价 ai。
* 输出格式
* 输出仅一个整数,表示最小代价。
* 数据范围
* 1≤n,m≤2×10^5,
* 0≤ai≤1000
* 输入样例:
* 5 3
* 1 2 5 6 2
* 输出样例:
* 4
* https://blog.csdn.net/qq_30277239/article/details/104580927
* f[i]表示前1~i且点燃第i个烽火台,
* 属性:最小代价
* f[i]找倒数第2个, i-1 i-2...i-m+1 i-m
* f[i]=min(f[j] | i-m<=j<i )+w[i] 单调队列优化
* 本题属于单调队列优化DP的简单问题,
* 状态表示:f[i]表示前i个烽火台中第i个烽火台发出了信号的最少代价。
* 当然也可以使用状态机去解决,这里暂且用基本的线性DP的解法去解决,
* 则状态转移方程为f[i] = min(f[j]) + w[i],其中i - m <= j < i。
* 直接写时间复杂度是O(mn),显然会超时,由于f[i]最多仅用到了前面的m个状态,
* 所以可以使用单调队列优化,用单调队列求出区间长度是m的窗口中f的最小值。
* 单调队列的具体实现不再赘述,只需要注意两点即可。
* 第一点,连续m个烽火台中至少有一个要发出信号,需要仔细的理解这句话,
* 比如m = 3时,烽火台1 2 3 4 5 6,如果6发出信号,那么4 5 6这三个连续的烽火台就有了可以发出信号的烽火,
* 意味着上一个发出信号的最早可以是3,也就是枚举时i = 6,队头元素最小可以是3,
* 即i - q[hh] > m时才需要出队头,不需要加等号,这里容易出错。
* 第二点就是单调队列实现步骤中更新f[i]语句的位置,由于f[i]需要放进队列中,
* 所以需要先计算完f[i]才能够再与队尾元素比较来决定f[i]在队列中的最终位置。具体实现见代码:
*/
public class 烽火传递 {
public static void main(String[] args) throws IOException {
......
......@@ -28,6 +28,15 @@ import java.util.Scanner;
* 输出样例:
* 1
* 先预处理求每行的最值,在预处理列
* 先对矩阵逐行求区间长度是n的滑动窗口的最大最小值,分别存进最大最小值数组。
* 然后再对求出的最值数组按列再求一次最值,
* 二者之差就是所有n*n正方形区域内的最大整数与最小整数差了。当然,求滑动区间的最值就是使用单调队列实现的。
* 如图所示,如果要求3*3正方形中的最值,
* 可以先将各行中长度为3的区间的最值存在这个区间开始的格子里,比如上图蓝色的区域,
* 求完后,第一列的前三个格子就存了这个蓝色正方形各行的最值,
* 再竖着对第一行求下长度为3区间的最值存到第一个单元格里,第一个单元格存储的就是整个正方形区域内的最值了。
* 当然我们是先把初始矩形各行长度为n区间的最值存到一个新的数组,然后再对这个数组竖着求最值存入又一个数组来实现的,
* 以避免值被覆盖。实现细节见代码:
*/
public class 理想的正方形 {
public static void main(String[] args) {
......@@ -41,14 +50,33 @@ public class 理想的正方形 {
}
}
for (int i = 1; i <= n; i++) {
getMin(w[i], row_min[i], m);
getMax(w[i], row_max[i], m);
}
int[] a = new int[N];
int[] b = new int[N];
int[] c = new int[N];
int res = (int) 1e9;
for (int i = k; i <= m; i++) {
for (int j = 1; j <= n; j++) {
a[j] = row_min[j][i];
}
getMin(a, b, n);
for (int j = 1; j <= n; j++) {
a[j] = row_max[j][i];
}
getMax(a, c, n);
for (int j = k; j <= n; j++) {
res = Math.min(res, c[j] - b[j]);
}
}
System.out.println(res);
}
static void getMin(int[] a, int[] b, int tot) {
int hh = 0, tt = -1;
for (int i = 1; i <= tot; i++) {
if (hh <= tt && q[hh] <= i - tot) hh++;
if (hh <= tt && q[hh] <= i - k) hh++;
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = i;
b[i] = a[q[hh]];
......@@ -58,7 +86,7 @@ public class 理想的正方形 {
static void getMax(int[] a, int[] b, int tot) {
int hh = 0, tt = -1;
for (int i = 1; i <= tot; i++) {
if (hh <= tt && q[hh] <= i - tot) hh++;
if (hh <= tt && q[hh] <= i - k) hh++;
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = i;
b[i] = a[q[hh]];
......
package graph;
import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.StringTokenizer;
import static java.lang.System.in;
public class AcWingEK {
public static void main(String[] args) throws IOException {
n = nextInt();
m = nextInt();
s = nextInt();
t = nextInt();
int a, b, c;
for (int i = 1; i <= m; i++) {
a = nextInt();
b = nextInt();
c = nextInt();
add(a, b, c);
}
System.out.println(ek());
}
static int cnt = 1, n, inf = (int) 1e9, t, s, m;
static int[] h = new int[1010];
static int[] e = new int[20010];
static int[] ne = new int[20010];
static int[] w = new int[20010];
static boolean[] st = new boolean[1202];
static int[] dis = new int[1202];
static int[] pre = new int[1010];
//加双向边
static void add(int a, int b, int c) {
e[++cnt] = b;
w[cnt] = c;
ne[cnt] = h[a];
h[a] = cnt;
e[++cnt] = a;
w[cnt] = 0;
ne[cnt] = h[b];
h[b] = cnt;
}
static ArrayDeque<Integer> q = new ArrayDeque<Integer>();
//使用bfs寻找增广路
static boolean bfs() {
Arrays.fill(st, false);
q.clear();
q.push(s);
st[s] = true;
dis[s] = inf;
while (!q.isEmpty()) {
int x = q.pollFirst();
for (int i = h[x]; i != 0; i = ne[i]) {
int v = e[i];
if (!st[v] && w[i] != 0) {
dis[v] = Math.min(dis[x], w[i]);
pre[v] = i;
q.push(v);
st[v] = true;
if (v == t) return true;
}
}
}
return false;
}
static int ek() {
int r = 0;
while (bfs()) {
r += dis[t];
for (int i = t; i != s; i = e[pre[i] ^ 1]) {
w[pre[i]] -= dis[t];
w[pre[i] ^ 1] += dis[t];
}
}
return r;
}
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static BufferedReader reader = new BufferedReader(new InputStreamReader(in));
static StringTokenizer tokenizer = new StringTokenizer("");
static String nextLine() throws IOException {// 读取下一行字符串
return reader.readLine();
}
static String next() throws IOException {// 读取下一个字符串
while (!tokenizer.hasMoreTokens()) {
//如果没有字符了,就是下一个,使用空格拆分,
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {// 读取下一个int型数值
return Integer.parseInt(next());
}
static double nextDouble() throws IOException {// 读取下一个double型数值
return Double.parseDouble(next());
}
}
package graph;
import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.StringTokenizer;
import static java.lang.System.in;
public class EK {
public static void main(String[] args) throws IOException {
n = nextInt();
m = nextInt();
s = nextInt();
t = nextInt();
int a, b, c;
for (int i = 1; i <= m; i++) {
a = nextInt();
b = nextInt();
c = nextInt();
if (flag[a][b] == 0) {
add(a, b, c);
flag[a][b] = cnt;
} else {
w[flag[a][b] - 1] += c;
}
}
while (bfs()) {
update();
}
System.out.println(ans);
}
static int[][] flag = new int[1001][1001];
static int cnt = 1, n, inf = Integer.MAX_VALUE / 2, t, s, ans = 0, m;
static int[] h = new int[1010];
static int[] e = new int[20010];
static int[] ne = new int[20010];
static int[] w = new int[20010];
static boolean[] st = new boolean[1002];
static int[] dis = new int[1002];
static int[] pre = new int[1010];
//加双向边
static void add(int a, int b, int c) {
e[++cnt]=b;
w[cnt]=c;
ne[cnt]=h[a];
h[a]=cnt;
e[++cnt]=a;
w[cnt]=0;
ne[cnt]=h[b];
h[b]=cnt;
}
static ArrayDeque<Integer> q = new ArrayDeque<Integer>();
//使用bfs寻找增广路
static boolean bfs() {
Arrays.fill(st, false);
q.clear();
q.push(s);
st[s] = true;
dis[s] = inf;
while (!q.isEmpty()) {
int x = q.pollFirst();
for (int i = h[x]; i != 0; i = ne[i]) {
if (w[i] == 0) continue;
int v = e[i];
if (st[v]) continue;
dis[v] = Math.min(dis[x], w[i]);
pre[v] = i;
q.push(v);
st[v] = true;
if (v == t) return true;
}
}
return false;
}
static void update() {
int x = t;
while (x != s) {
int v = pre[x];
w[v] -= dis[t];
w[v ^ 1] += dis[t];
x = e[v ^ 1];
}
ans += dis[t];
}
static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
static BufferedReader reader = new BufferedReader(new InputStreamReader(in));
static StringTokenizer tokenizer = new StringTokenizer("");
static String nextLine() throws IOException {// 读取下一行字符串
return reader.readLine();
}
static String next() throws IOException {// 读取下一个字符串
while (!tokenizer.hasMoreTokens()) {
//如果没有字符了,就是下一个,使用空格拆分,
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {// 读取下一个int型数值
return Integer.parseInt(next());
}
static double nextDouble() throws IOException {// 读取下一个double型数值
return Double.parseDouble(next());
}
}
package graph.有向图的强联通分量;
/**
*
*/
@SuppressWarnings("all")
public class 受欢迎的牛 {
public static void main(String[] args) {
}
// static void tarjar(int u) {
// dfu[u] = low[u] = ++time;
// stk[++top] = u;
// in_stk[u] = true;
// for (int i = he[u]; i != 0; i = ne[i]) {
// int j=e[i];
// if (!dfn[j]){
// tarjar(j);
// low[u]=Math.min(low[u],low[j]);
// }else if (in_stk[j])
// low[u]=Math.min(low[u],dfn[j]);
// }
// if (dfn[u]==low[u]){
// int y;
// ++scc_cnt;
// do {
// y=stk[top--];
// in_stk[y]=false;
// id[y]=scc_cnt;
// }while (y!=u);
// }
// }
}
......@@ -13,3 +13,12 @@
后向边
横叉边
SCC强连通分量
1.某一点是否在强连通分量里面,存在后向边指向祖先节点,
2.先走到横叉边,横叉边再走到祖先节点
基于tarjan求强连通分量(SCC)
引入时间戳
dfn[u]遍历到u的时间
low[u]记录从u开始走,所能遍历到的最小时间戳是什么
u是其所在强连通分量的最高点,等价于dfn[u]==low[u]
package graph;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
/**
*
*/
public class 洛谷二分图最大匹配 {
public static void main(String[] args) {
}
static int n, m, N = 510, M = 5000;
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st = new StringTokenizer("");
static String next() throws IOException {
while (!st.hasMoreTokens()) {
st = new StringTokenizer(br.readLine());
}
return st.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册