拓扑排序+链式前向星
*
因为若有环,则环内的点不会入队列被访问,所以可以判环
import java.io.*;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
class Tx1{
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int m=input.nextInt();
head=new int[n+1];
e=new Edge[m<<1|1];
cnt=0;
int[] in=new int[n+1];
for(int i=1;i<=m;++i) {
int x=input.nextInt();
int y=input.nextInt();
addEdge(x, y, 0);
in[y]++;
}
int tot=0;
int[] turn=new int[n+1];
Queue<Integer> que=new LinkedList<Integer>();
for(int i=1;i<=n;++i) {
if(in[i]==0) {
tot++;
turn[tot]=i;
que.add(i);
}
}
while(!que.isEmpty()) {
int x=que.peek();
que.poll();
for(int i=head[x];i>0;i=e[i].nxt) {
int t=e[i].to;
in[t]--;
if(in[t]==0) {
tot++;
turn[tot]=t;
que.add(t);
}
}
}
if(tot!=n) {
out.println("-1");
}else {
for(int i=1;i<=n;++i) {
out.print(turn[i]+" ");
}
}
out.flush();
out.close();
}
static
class Edge{
int fr;
int to;
int val;
int nxt;//下一条边的位置
}
static int[] head;
static Edge[] e;
static int cnt;
public static void addEdge(int fr,int to,int val) {
cnt++;
e[cnt]=new Edge();
e[cnt].fr=fr;
e[cnt].to=to;
e[cnt].val=val;
e[cnt].nxt=head[fr];//最后循环是倒着往前找边
head[fr]=cnt;
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}
AOE网络图
*
- 一个有向连通图,存在一个源点,一个汇点。
- 每个边表示一项任务,边权即为完成该任务所需的时间,这条边指向的节点称作验收节点。
- 每个验收节点,只有当它的所有入边的任务均完成,才能继续往下走。
问:
最终至少需要多长时间完成所有任务?
哪些任务是影响总时间的关键?(即一旦延期则总时间增长)
解:
先正向进行拓扑排序,每当一个点入度减一时,维护该点验收的最少时间(即所有入边中累计边权最大的),同时记录相应的入边。最终汇点的
即为至少所需的时间。
建立反向图。
再反向进行拓扑排序,每当一个点入度减一时,维护该点进行下一项任务的最少时间(即其所有入边节点的
减去入边的边权中最小的)
最后对于每个节点,若则说明该点验收完立马进行下一项任务,所以该点维护的入边即为关键任务。
最短路
Dijkstra
- 求单源最短路。
- 初始除出发点外,距离全为
,出发点入小根堆,距离为0。
- 小根堆按照距离排序。
- 之后依次从堆中取出当前未访问且累计距离最近的点
,标记为访问过,更新与其相连的点
的距离,
,若更新则入堆。
- 当堆为空时,最短路求解完毕。
- 不能处理存在负边权
import java.io.*;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main{
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int m=input.nextInt();
int s=input.nextInt();
cnt=0;
head=new int[n+1];
e=new Edge[m<<1|1];
for(int i=1;i<=m;++i) {
int u=input.nextInt();
int v=input.nextInt();
long w=input.nextLong();
addEdge(u, v, w);
}
PriorityQueue<Node> que=new PriorityQueue<>
((o1,o2)->{
if(o1.dis-o2.dis==0L) {
return 0;
}else if(o1.dis-o2.dis<0L) {
return -1;
}else return 1;
});
long[] dis=new long[n+1];
for(int i=1;i<=n;++i) {
dis[i]=Long.MAX_VALUE;
}
boolean[] vis=new boolean[n+1];
dis[s]=0;
que.add(new Node(s, 0));
while(!que.isEmpty()) {
Node now=que.peek();
que.poll();
int u=now.id;
if(vis[u])continue;
long disu=now.dis;
vis[u]=true;
for(int i=head[u];i>0;i=e[i].nxt) {
int v=e[i].to;
long w=e[i].val;
if(dis[v]>disu+w) {
dis[v]=disu+w;
que.add(new Node(v, dis[v]));
}
}
}
for(int i=1;i<=n;++i) {
out.print(dis[i]+" ");
}
out.flush();
out.close();
}
static
class Node{
int id;
long dis;
public Node(int I,long X) {
id=I;
dis=X;
}
}
static
class Edge{
int fr;
int to;
long val;
int nxt;//下一条边的位置
}
static int[] head;
static Edge[] e;
static int cnt;
public static void addEdge(int fr,int to,long val) {
cnt++;
e[cnt]=new Edge();
e[cnt].fr=fr;
e[cnt].to=to;
e[cnt].val=val;
e[cnt].nxt=head[fr];//最后循环是倒着往前找边
head[fr]=cnt;
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}
SPFA
,
为每点平均入队次数,最劣会到
,求无环最长路不如直接用
- 就是在
的每轮对于每个点都进行扫描看能否对后继点进行更新,直到该轮无法进行更新的暴力上进行优化。
- 由于可能会对一个不会更新后继的点进行重复访问,造成不必要的时间消耗。
- 采用队列优化。
- 若当前点
的距离
没有更新,则对于其后继也不会有影响,所以不入队列。
- 若
更新,则其后继也要更新。
- 若
在队列中,则把这次更新看作和入队那次更新为一轮更新,不入队列。
- 若
不在队列中,则入队列,对后继进行更新。
- 对于负权图,使用
,对于正权图,使用
- 若存在一点
,进入队列超过
次,即所有点都对它进行更新后,还能进行更新,则存在负环
package Tx;
import java.io.*;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
class Tx1{
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int m=input.nextInt();
int s=input.nextInt();
int t=input.nextInt();
cnt=0;
head=new int[n+1];
e=new Edge[m<<1|1];
for(int i=1;i<=m;++i) {
int u=input.nextInt();
int v=input.nextInt();
long w=input.nextLong();
addEdge(u, v, w);
addEdge(v, u, w);//无向边
}
Queue<Integer> que=new LinkedList<Integer>();
long[] dis=new long[n+1];
boolean[] inque=new boolean[n+1];
for(int i=1;i<=n;++i) {
dis[i]=Long.MAX_VALUE;
}
dis[s]=0;
que.add(s);
inque[s]=true;
while(!que.isEmpty()) {
int u=que.peek();
que.poll();
inque[u]=false;//出队列
for(int i=head[u];i>0;i=e[i].nxt) {
int v=e[i].to;
long w=e[i].val;
if(dis[v]>dis[u]+w) {
dis[v]=dis[u]+w;
if(inque[v])continue;
que.add(v);
inque[v]=true;
}
}
}
if(dis[t]==Long.MAX_VALUE){
out.println("-1");
}else{
out.println(dis[t]);
}
out.flush();
out.close();
}
static
class Node{
int id;
long dis;
public Node(int I,long X) {
id=I;
dis=X;
}
}
static
class Edge{
int fr;
int to;
long val;
int nxt;//下一条边的位置
}
static int[] head;
static Edge[] e;
static int cnt;
public static void addEdge(int fr,int to,long val) {
cnt++;
e[cnt]=new Edge();
e[cnt].fr=fr;
e[cnt].to=to;
e[cnt].val=val;
e[cnt].nxt=head[fr];//最后循环是倒着往前找边
head[fr]=cnt;
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}
Floyed
- 利用动态规划求解任意两点之间的最短路
表示从
到
,只可能经过
编号的点的最短路,
- 最外层枚举
,保证路径长度由小到大,则
可以在状态中省去
- 邻接矩阵存图,直接相连的边对
初始化,即得出路径长度为1的
for(int k=1;i<=n;++i) {
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) {
if((i!=j)&&(j!=k)&&(i!=k)) {
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
}
}
}
}
最小生成树
Prim
- 从任意点出发,由点发散成树
- 用
记录已经在树上的点
- 加边考虑由树上的点发出的最短的树枝,与
相似
- 但不是到出发点的累计距离,而是相邻点的直接距离
- 利用堆取出最小值为新加的边,然后接着扩展
的边有向
import java.io.*;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Main{
static int cnt=0;
static Edge[] e;
static int[] head;
static
class Edge{
long val;
int to;
int fr;
int nxt;
}
static void addEdge(int fr,int to,long val) {
cnt++;
e[cnt]=new Edge();
e[cnt].fr=fr;
e[cnt].to=to;
e[cnt].val=val;
e[cnt].nxt=head[fr];
head[fr]=cnt;
}
static
class Node{
int x;
long dis;
public Node() {}
public Node(int I,long D) {
x=I;;
dis=D;
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int m=input.nextInt();
e=new Edge[2*m+1];
head=new int[n+1];
for(int i=1;i<=m;++i) {
int a=input.nextInt();
int b=input.nextInt();
long val=input.nextLong();
addEdge(a, b, val);
addEdge(b, a, val);
}
PriorityQueue<Node> qu=new PriorityQueue<Node>((o1,o2)->{
if(o1.dis-o2.dis<0)return -1;
else if(o1.dis-o2.dis>0)return 1;
else return 0;
});
boolean[] vis=new boolean[n+1];
long ans=0;
qu.add(new Node(1, 0));
while(!qu.isEmpty()) {
Node now=qu.peek();
qu.poll();
int x=now.x;
if(vis[x])continue;
ans+=now.dis;
vis[x]=true;
for(int i=head[x];i>0;i=e[i].nxt) {
int v=e[i].to;
long disv=e[i].val;
if(vis[v]==false) {
qu.add(new Node(v,disv));
}
}
}
out.print(ans);
out.flush();
out.close();
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}
Kruskal
为无向边
- 对所有的边由小到大进行排序,依次取边,进行点合并
- 用并查集维护点合并,不在一个集合内的边才要
- 共合并
次
import java.io.*;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Main{
static int cnt=0;
static Edge[] e;
static int[] head;
static
class Edge{
long val;
int to;
int fr;
int nxt;
}
static void addEdge(int fr,int to,long val) {
cnt++;
e[cnt]=new Edge();
e[cnt].fr=fr;
e[cnt].to=to;
e[cnt].val=val;
e[cnt].nxt=head[fr];
head[fr]=cnt;
}
static int[] fa;
static int[] size;
static int find(int x) {
if(x==fa[x])return x;
else return fa[x]=find(fa[x]);
}
static void merge(int x,int y){
if(size[x]>size[y]){
fa[y]=x;
size[x]++;
}else{
fa[x]=y;
size[y]++;
}
}
static
class Node{
int x;
long dis;
public Node() {}
public Node(int I,long D) {
x=I;;
dis=D;
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int m=input.nextInt();
e=new Edge[2*m+1];
fa=new int[n+1];
size=new int[n+1];
head=new int[n+1];
for(int i=1;i<=m;++i) {
int a=input.nextInt();
int b=input.nextInt();
long val=input.nextLong();
cnt++;
e[cnt]=new Edge();
e[cnt].fr=a;
e[cnt].to=b;
e[cnt].val=val;
}
for(int i=1;i<=n;++i)fa[i]=i;
Arrays.sort(e,1,cnt+1,(o1,o2)->{
if(o1.val-o2.val<0)return -1;
else if(o1.val-o2.val>0)return 1;
else return 0;
});
int t=0;
long ans=0;
for(int i=1;i<=cnt;++i) {
int u=e[i].fr;
int v=e[i].to;
int fau=find(u);
int fav=find(v);
if(fau==fav)continue;
merge(fau,fav);
ans+=e[i].val;
t++;
if(t==n-1)break;
}
out.print(ans);
out.flush();
out.close();
}
static
class AReader {
private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private StringTokenizer tokenizer = new StringTokenizer("");
private String innerNextLine() {
try {
return reader.readLine();
} catch (IOException ex) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String nextLine = innerNextLine();
if (nextLine == null) {
return false;
}
tokenizer = new StringTokenizer(nextLine);
}
return true;
}
public String nextLine() {
tokenizer = new StringTokenizer("");
return innerNextLine();
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}
唯一最小生成树
- 通过删边得到唯一最小生成树,问最小代价
- 修改
,排完序后,值相同的边会删去一些留下一些(值相同的边先后顺序无影响)
- 对于集合内的添边删去
黑白染色
扩展并查集
- 将
个点,建立相应的对立点,扩展为
,即
的对立点为
,
白
黑,
黑
白
- 有
,即
不同染色,所以
同染色,放一起,
同染色,放一起
- 若没有取在相同集合点进行连边,则黑白染色成功
带权并查集
- 将
不同染色看作对
进行边权为1的连边,会产生连通图
- 对于连通图上的点
,若
距离为
,
,则
相同染色,
则不同染色
- 考虑并查集,将任意两点的关系,变为知道集合内点与最大祖先的关系,然后再进行比较得出关系
- 考虑路径压缩维护关系传递,对于集合内的点,记录与直接父亲的关系即可,在
过程中得出与最大祖先的关系,此时由于路径压缩最大祖先也变为了直接父亲
- 考虑合并,
,加2保证为正数,
实际不相连
例:食物链(A,B,C三染色)
- 同理,若用扩展并查集,一个点相应有3个,扩展为
,进行并查集维护
- 同理,若用带权并查集,关系有
,模3进行维护扩展并查集
扩展并查集
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.Vector;
public class Main{
static int find(int x,int[] fa) {
if(x==fa[x])return x;
else return fa[x]=find(fa[x], fa);
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int k=input.nextInt();
int[] fa=new int[3*n+1];
for(int i=1;i<=3*n;++i)fa[i]=i;
int ans=0;
for(int i=1;i<=k;++i) {
int op=input.nextInt();
int x=input.nextInt();
int y=input.nextInt();
if(x>n||y>n) {
ans++;
continue;
}
if(op==1) {
if(find(x, fa)==find(y+n, fa)||find(y, fa)==find(x+n, fa)) {
//x吃y或y吃x
//x吃y=>xA->yB,xB->yC,xC->yA
//y吃x=>yA->xB,yB->xC->yC->xA
ans++;
continue;
}
fa[find(x, fa)]=find(y, fa);
fa[find(x+n, fa)]=find(y+n, fa);
fa[find(x+2*n, fa)]=find(y+2*n, fa);
}else {
if(x==y) {
ans++;
continue;
}
if(find(x, fa)==find(y, fa)||find(y, fa)==find(x+n, fa)) {
//x和y是同类,y吃x
ans++;
continue;
}
fa[find(x, fa)]=find(y+n, fa);
fa[find(x+n, fa)]=find(y+2*n, fa);
fa[find(x+2*n, fa)]=find(y, fa);
}
}
out.print(ans);
out.flush();
out.close();
}
static
class AReader{
BufferedReader bf;
StringTokenizer st;
BufferedWriter bw;
public AReader(){
bf=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer("");
bw=new BufferedWriter(new OutputStreamWriter(System.out));
}
public String nextLine() throws IOException{
return bf.readLine();
}
public String next() throws IOException{
while(!st.hasMoreTokens()){
st=new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
public char nextChar() throws IOException{
//确定下一个token只有一个字符的时候再用
return next().charAt(0);
}
public int nextInt() throws IOException{
return Integer.parseInt(next());
}
public long nextLong() throws IOException{
return Long.parseLong(next());
}
public double nextDouble() throws IOException{
return Double.parseDouble(next());
}
public float nextFloat() throws IOException{
return Float.parseFloat(next());
}
public byte nextByte() throws IOException{
return Byte.parseByte(next());
}
public short nextShort() throws IOException{
return Short.parseShort(next());
}
public BigInteger nextBigInteger() throws IOException{
return new BigInteger(next());
}
public void println() throws IOException {
bw.newLine();
}
public void println(int[] arr) throws IOException{
for (int value : arr) {
bw.write(value + " ");
}
println();
}
public void println(int l, int r, int[] arr) throws IOException{
for (int i = l; i <= r; i ++) {
bw.write(arr[i] + " ");
}
println();
}
public void println(int a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(int a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(String a) throws IOException{
bw.write(a);
bw.newLine();
}
public void print(String a) throws IOException{
bw.write(a);
}
public void println(long a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(long a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(double a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(double a) throws IOException{
bw.write(String.valueOf(a));
}
public void print(char a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(char a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
}
}
带权并查集
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.Vector;
public class Main{
static int find(int x,int[] fa,int[] relation) {
if(x==fa[x])return x;
else {
int f=fa[x];
fa[x]=find(fa[x], fa, relation);
relation[x]=(relation[x]+relation[f])%3;
return fa[x];
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
int k=input.nextInt();
int ans=0;
int[] fa=new int[n+1];
int[] relation=new int[n+1];
for(int i=1;i<=n;++i) fa[i]=i;
for(int i=1;i<=k;++i) {
int op=input.nextInt();
int x=input.nextInt();
int y=input.nextInt();
if(x>n||y>n) {
ans++;
continue;
}
if(op==1) {
int fx=find(x, fa, relation);
int fy=find(y, fa, relation);
if(fx==fy) {
if(relation[x]!=relation[y]) {
ans++;
continue;
}
}else {
fa[fx]=fy;
relation[fx]=(relation[y]+0-relation[x]+3)%3;
}
}else {
if(x==y) {
ans++;
continue;
}
int fx=find(x, fa, relation);
int fy=find(y, fa, relation);
if(fx==fy) {//0吃1,1吃2,2吃0
if(relation[x]==0&&relation[y]==1||
relation[x]==1&&relation[y]==2||
relation[x]==2&&relation[y]==0)continue;
ans++;
continue;
}else {
fa[fx]=fy;
relation[fx]=(relation[y]+2-relation[x]+3)%3;
}
}
}
out.println(ans);
out.flush();
out.close();
}
static
class AReader{
BufferedReader bf;
StringTokenizer st;
BufferedWriter bw;
public AReader(){
bf=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer("");
bw=new BufferedWriter(new OutputStreamWriter(System.out));
}
public String nextLine() throws IOException{
return bf.readLine();
}
public String next() throws IOException{
while(!st.hasMoreTokens()){
st=new StringTokenizer(bf.readLine());
}
return st.nextToken();
}
public char nextChar() throws IOException{
//确定下一个token只有一个字符的时候再用
return next().charAt(0);
}
public int nextInt() throws IOException{
return Integer.parseInt(next());
}
public long nextLong() throws IOException{
return Long.parseLong(next());
}
public double nextDouble() throws IOException{
return Double.parseDouble(next());
}
public float nextFloat() throws IOException{
return Float.parseFloat(next());
}
public byte nextByte() throws IOException{
return Byte.parseByte(next());
}
public short nextShort() throws IOException{
return Short.parseShort(next());
}
public BigInteger nextBigInteger() throws IOException{
return new BigInteger(next());
}
public void println() throws IOException {
bw.newLine();
}
public void println(int[] arr) throws IOException{
for (int value : arr) {
bw.write(value + " ");
}
println();
}
public void println(int l, int r, int[] arr) throws IOException{
for (int i = l; i <= r; i ++) {
bw.write(arr[i] + " ");
}
println();
}
public void println(int a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(int a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(String a) throws IOException{
bw.write(a);
bw.newLine();
}
public void print(String a) throws IOException{
bw.write(a);
}
public void println(long a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(long a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(double a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
public void print(double a) throws IOException{
bw.write(String.valueOf(a));
}
public void print(char a) throws IOException{
bw.write(String.valueOf(a));
}
public void println(char a) throws IOException{
bw.write(String.valueOf(a));
bw.newLine();
}
}
}
分层图
路径决策
相对于普通最短路,其每个点多了状态设置,即点自己本身有不同的状态,对应其连边有不同的边权。
通过按状态拆点添新边(不进行决策可以直接跑),建整合点(减少建边复杂程度,压缩路径)
状态有:当前点的颜色,当前点的操作数,棋盘上当前点的上下左右方向
P1948 [USACO08JAN] Telephone Lines S
P2937 [USACO09JAN] Laserphones S
最大生成树
*
- 先找出树的直径,然后按其他点到直径端点最远的距离添边
- 找出树的直径只需找出一个非叶子节点,找出距离最远的两个点即为直径端点