内容:,拆点,分层,传递,带限制的最小生成树
[HNOI2015]菜肴制作
题目链接
题目大意
- 有个限制,号菜肴在号前完成
- 在满足限制的条件下,按照出菜( 是为了满足的限制 )
解题思路
- 由限制,可以考虑
- 若直接正向,以 为例, 则会先出
- 而反向,
- 此时对于一路限制,最先出的最小的号
- 题目有要求先满足较小号的限制
- 所以将队列改为由大到小排序的堆,再倒序输出每次出堆的号
- 排序的内容实际为正向限制路径上的最终菜肴
- 有环则无解
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 T=input.nextInt();
while(true) {
if(T==0) break;
int n=input.nextInt();
int m=input.nextInt();
e=new Edge[m+1];
head=new int[n+1];
cnt=0;
int[] in=new int[n+1];
for(int i=1;i<=m;++i) {
int u=input.nextInt();
int v=input.nextInt();
in[u]++;
addEdge(v, u, 0);
}
PriorityQueue<Integer> qu=new PriorityQueue<Integer>((o1,o2)-> {return o2-o1;});
boolean[] vis=new boolean[n+1];
for(int i=1;i<=n;++i) {
if(in[i]==0) {
qu.add(i);
vis[i]=true;
}
}
int[] op=new int[n+1];
int cnt=0;
while(!qu.isEmpty()) {
int x=qu.peek();
qu.poll();
cnt++;
op[cnt]=x;
for(int i=head[x];i>0;i=e[i].nxt) {
int v=e[i].to;
if(vis[v])continue;
in[v]--;
if(in[v]==0) {
qu.add(v);
vis[v]=true;
}
}
}
if(cnt!=n) {
out.println("Impossible!");
}else {
for(int i=cnt;i>0;--i) {
out.print(op[i]+" ");
}
out.println();
}
T--;
}
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());
}
}
}
胖胖的牛牛
题目链接
题目大意
- 在图上从到,不可经过,有水平和垂直两个方向
- 在且方向为垂直,往左或右走,需要转变方向
- 求最少的转变方向次数
解题思路
- 将,看作两步,先判断转向,再移动
- 所以将一个点拆为上下左右4个,
- ,,
- 求拆点后,的最短路
import java.io.*;
import java.io.ObjectInputStream.GetField;
import java.math.BigInteger;
import java.util.Arrays;
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 inf=Integer.MAX_VALUE/2;
static
class Edge{
int fr,to,nxt;
int val;
public Edge(int u,int v,int w) {
fr=u;
to=v;
val=w;
}
}
static
class Node{
int x,y;
public Node(int X,int Y) {
x=X;
y=Y;
}
}
static
class Map{
int[] head;
int cnt;
Edge[] e;
int ans=inf;
public Map(int n,int m) {
e=new Edge[m];
head=new int[n+1];
cnt=0;
}
void addEdge(int fr,int to,int val) {
cnt++;
e[cnt]=new Edge(fr, to, val);
e[cnt].nxt=head[fr];
head[fr]=cnt;
}
void Dij(int s,int n,int[] t) {
int[] dis=new int[n+1];
boolean[] vis=new boolean[n+1];
PriorityQueue<Node> q=new PriorityQueue<Node>((o1,o2)->{return o1.y-o2.y;});
for(int i=1;i<=n;++i)dis[i]=inf;
dis[s]=0;
q.add(new Node(s, 0));
while(!q.isEmpty()) {
Node now=q.peek();
q.poll();
int x=now.x;
if(vis[x])continue;
int disu=now.y;
for(int i=head[x];i>0;i=e[i].nxt) {
int v=e[i].to;
int w=e[i].val;
if(vis[v])continue;
if(dis[v]>disu+w) {
dis[v]=disu+w;
q.add(new Node(v,dis[v]));
}
}
}
ans=Math.min(ans, Math.min(dis[t[0]], dis[t[1]]));
}
}
public static void main(String[] args) throws IOException{
AReader input=new AReader();
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
int n=input.nextInt();
char[][] map=new char[n+1][n+1];
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j)map[i][j]=input.nextChar();
}
int N=4*n*n;
Map T=new Map(N, 200000);
int[] s=new int[2];
int[] t=new int[2];
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) {
if(map[i][j]=='x')continue;
int num=(i-1)*n+j;
int l=(num-1)*4;
int u=l+1;
int r=l+2;
int v=l+3;
T.addEdge(l, u, 1);
T.addEdge(u, l, 1);
T.addEdge(u, r, 1);
T.addEdge(r, u, 1);
T.addEdge(r, v, 1);
T.addEdge(v, r, 1);
T.addEdge(v, l, 1);
T.addEdge(l, v, 1);
T.addEdge(l, r, 0);
T.addEdge(r, l, 0);
T.addEdge(u, v, 0);
T.addEdge(v, u, 0);
if(j+1<=n&&map[i][j+1]!='x') {
int nxtl=num*4;
T.addEdge(r, nxtl, 0);
T.addEdge(nxtl, r, 0);
}
if(j>=2&&map[i][j-1]!='x') {
int nxtr=(num-2)*4+2;
T.addEdge(nxtr, l, 0);
T.addEdge(l, nxtr, 0);
}
if(i>=2&&map[i-1][j]!='x') {
int nxtv=((i-2)*n+j-1)*4+3;
T.addEdge(u, nxtv, 0);
T.addEdge(nxtv, u, 0);
}
if(i+1<=n&&map[i+1][j]!='x') {
int nxtu=(i*n+j-1)*4+1;
T.addEdge(nxtu, v, 0);
T.addEdge(v, nxtu, 0);
}
if(map[i][j]=='A') {
s[0]=l;
s[1]=u;
}else if(map[i][j]=='B') {
t[0]=l;
t[1]=u;
}
}
}
T.Dij(s[0], N, t);
T.Dij(s[1], N, t);
if(T.ans==inf)out.print("-1");
else out.print(T.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();
}
}
}
UVALive7250 Meeting
题目大意
- 个点,个集合,集合内的点有权为的边
- 从出发,从出发,走单位距离花费时间,问相遇与一点的最少时间
解题思路
- 若点集合,任意两点之间连边,共连,当很大存不下
- 考虑将集合看作一点,则集合内两点连边,变为
- 连边降为,可以存下
- 在个点上的任意一点相遇
- 以和为出发点,跑最短路
- 再枚举点,求
[USACO 2007 Mar G] Ranking the cows
题目链接
题目大意
- 有 个数字,已经比较了对
- 问至少还需要多少对比较,可以将个数由大到小排列
解题思路
- 对于,若已知,则
- ,类似枚举中间点
- 定义表示
- 可以省去枚举,
- 表示与其他点的状态,用
- 若,则不知道大小关系,需要比较,
- 此时不知道比较后的结果,无法传递,要满足至少都得比较
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.BitSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.Vector;
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();
BitSet[] a=new BitSet[n+1];
for(int i=0;i<n;++i)a[i]=new BitSet(n);
for(int i=1;i<=m;++i) {
int x=input.nextInt()-1;
int y=input.nextInt()-1;
a[x].set(y);//对应位置赋为true
}
for(int k=0;k<n;++k) {
for(int i=0;i<n;++i) {
if(a[i].get(k)) {
a[i].or(a[k]);//或运算
}
}
}
int ans=0;
for(int i=0;i<n;++i) {
for(int j=i+1;j<n;++j) {
if(a[i].get(j)==false&&a[j].get(i)==false) {
ans++;
//因为不知道是i>j还是i<j,无法传递
}
}
}
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();
}
}
}
[SCOI2012]滑雪与时间胶囊
题目链接
题目大意
- 条边,每个边的端点为景点,共个
- 每个点有高度
- 能到,满足有,边权为
- 从从号景点出发,走最短路,访问尽量多的节点
- 同时可以回到经过的任意一个节点,再次出发
- 问最多能访问多少个节点和此时走过的最小路径长度
解题思路
- 由于可以任意回溯,所以可以访问到号节点能到的任意一个节点
- 设号节点能到的点数为,则最终边有条
- 考虑生成最小树
- 由于边有高度通行限制,所以要访问尽可能多的点,高度高的点先出,其次再比较边权
- 每出一个点,进行答案更新
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
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;
int h;
long dis;
public Node(){}
public Node(int X,long D,int H){
x=X;
h=H;
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();
int[] H=new int[n+1];
e=new Edge[m<<1|1];
head=new int[n+1];
for(int i=1;i<=n;++i) {
H[i]=input.nextInt();
}
for(int i=1;i<=m;++i) {
int u=input.nextInt();
int v=input.nextInt();
long val=input.nextLong();
if(H[u]>=H[v])addEdge(u, v, val);
if(H[v]>=H[u])addEdge(v, u, val);
}
boolean[] vis=new boolean[n+1];
PriorityQueue<Node> qu=new PriorityQueue<Node>((o1,o2)->{
if(o1.h==o2.h){
if(o1.dis-o2.dis>0)return 1;
else if(o1.dis-o2.dis<0)return -1;
else return 0;
}else return o2.h-o1.h;
});
int num=0;
long ans=0;
qu.add(new Node(1,0,H[1]));
while(!qu.isEmpty()) {
Node now=qu.peek();
qu.poll();
int x=now.x;
if(vis[x])continue;
vis[x]=true;
ans+=now.dis;
num++;
for(int i=head[x];i>0;i=e[i].nxt) {
int v=e[i].to;
long w=e[i].val;
if(vis[v])continue;
qu.add(new Node(v,w,H[v]));
}
}
out.println(num+" "+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());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
}