环境治理
环境治理
问题描述
LQ 国拥有 nn 个城市, 从 0 到 n−1n−1 编号, 这 nn 个城市两两之间都有且仅有 一条双向道路连接, 这意味着任意两个城市之间都是可达的。每条道路都有一 个属性 DD, 表示这条道路的灰尘度。当从一个城市 AA 前往另一个城市 BB 时, 可 能存在多条路线, 每条路线的灰尘度定义为这条路线所经过的所有道路的灰尘 度之和, LQ 国的人都很讨厌灰尘, 所以他们总会优先选择灰尘度最小的路线。
LQ 国很看重居民的出行环境, 他们用一个指标 PP 来衡量 LQ 国的出行环 境, PP 定义为:
P=∑i=0n−1∑j=0n−1d(i,j)P=i=0∑n−1j=0∑n−1d(i,j)
其中 d(i,j)d(i,j) 表示城市 ii 到城市 jj 之间灰尘度最小的路线对应的灰尘度的值。 为了改善出行环境, 每个城市都要有所作为, 当某个城市进行道路改善时, 会将与这个城市直接相连的所有道路的灰尘度都减少 1 , 但每条道路都有一个 灰尘度的下限值 LL, 当灰尘度达到道路的下限值时, 无论再怎么改善, 道路的 灰尘度也不会再减小了。
具体的计划是这样的:
第 1 天, 0 号城市对与其直接相连的道路环境进行改善;
第 2 天, 1 号城市对与其直接相连的道路环境进行改善;
⋯⋯
第 nn 天, n−1n−1 号城市对与其直接相连的道路环境进行改善;
第 n+1n+1 天, 0 号城市对与其直接相连的道路环境进行改善;
第 n+2n+2 天, 1 号城市对与其直接相连的道路环境进行改善;
LQ 国想要使得 PP 指标满足 P≤QP≤Q 。请问最少要经过多少天之后, PP 指标 可以满足 P≤QP≤Q 。如果在初始时就已经满足条件, 则输出 0 ; 如果永远不可能 满足, 则输出 −1−1 。
输入格式
输入的第一行包含两个整数 n,Qn,Q, 用一个空格分隔, 分别表示城市个数和 期望达到的 PP 指标。
接下来 nn 行, 每行包含 nn 个整数, 相邻两个整数之间用一个空格分隔, 其 中第 ii 行第 jj 列的值 Dij(Dij=Dji,Dii=0)Dij(Dij=Dji,Dii=0) 表示城市 ii 与城市 jj 之间直接相连 的那条道路的灰尘度。
接下来 nn 行, 每行包含 nn 个整数, 相邻两个整数之间用一个空格分隔, 其 中第 ii 行第 jj 列的值 Lij(Lij=Lji,Lii=0)Lij(Lij=Lji,Lii=0) 表示城市 ii 与城市 jj 之间直接相连的 那条道路的灰尘度的下限值。
输出格式
输出一行包含一个整数表示答条。
样例输入
3 10
0 2 4
2 0 1
4 1 0
0 2 2
2 0 0
2 0 0
样例输出
2
评测用例规模与约定
对于 30%30% 的评测用例, 1≤n≤10,0≤Lij≤Dij≤101≤n≤10,0≤Lij≤Dij≤10 ;
对于 60%60% 的评测用例, 1≤n≤50,0≤Lij≤Dij≤1000001≤n≤50,0≤Lij≤Dij≤100000;
对于所有评测用例, 1≤n≤100,0≤Lij≤Dij≤100000,0≤Q≤231−11≤n≤100,0≤Lij≤Dij≤100000,0≤Q≤231−1 。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;
public class Main {
static int N=110,M=2*10010,MAX_CNT=2*10000010;
static int n,q;
static int id=1;
static int cnt=-1;
static int dd[][]=new int[N][N];
static int d[][]=new int[N][N];
static int L[][]=new int[N][N];
// static int h[]=new int[M];
// static int e[]=new int[M];
// static int ne[]=new int[M];
// static int w[]=new int[M];
// static boolean f[]=new boolean[10010];//是否确定了最短路径
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
StringTokenizer st=new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
q=Integer.parseInt(st.nextToken());
for (int i = 1; i <= n; i++) {
st=new StringTokenizer(br.readLine());
for (int j = 1; j <= n; j++) {
d[i][j]=Integer.parseInt(st.nextToken());
d[j][i]=d[i][j];
}
}
for (int i = 1; i <= n; i++) {
st=new StringTokenizer(br.readLine());
for (int j = 1; j <= n; j++) {
L[i][j]=Integer.parseInt(st.nextToken());
L[j][i]=L[i][j];
}
}
//对于每一个城市i (这里我们编号从一开始) 给定一个时刻t 我们需要知道他被改善的次数
//次数等于t/n+(i<=t?1:0)也就是说先看看n个城市同时被改善的次数是多少
//然后再加上剩下的次数 这个剩下的次数取决于i和t的大小
//用二分枚举t
int l=0,r=MAX_CNT;//保证都能取到下限值嗯
while(l<r){
int mid=(l+r)>>1;
if(calc(mid)){
r=mid;
}else{
l=mid+1;
}
}
bw.write(cnt+"");
br.close();
bw.flush();
bw.close();
}
static boolean calc(int u){
int imporve[]=new int[n+1];//经过t天每个城市的改善次数
for (int i = 1; i <= n; i++) {
imporve[i]=u/n+(i-1<u%n?1:0);//注意没有等号
}
for (int i = 0; i < N; i++) {
System.arraycopy(d[i], 0, dd[i], 0, N);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dd[i][j]=Math.max(L[i][j], dd[i][j]-imporve[i]-imporve[j]);
}
}
//弗洛伊德算法
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
dd[i][j]=Math.min(dd[i][j],dd[i][k]+dd[k][j]);
}
}
}
int res=0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
res+=dd[i][j];
}
}
if(res<=q){
cnt=u;
return true;
}
return false;
}
// static void add(int a,int b,int c){
// e[id]=b;
// ne[id]=h[a];
// w[id]=c;
// h[a]=id++;
// }
}
染色时间
问题描述
小蓝有一个 nn 行 mm 列的白色棋盘, 棋盘的每一个方格都可以被染成彩色。
每个方格有一个染色时间 tijtij, 不同方格的染色时间可能不同。如果一个方 格被触发了染色, 这个方格就会在 tijtij 秒之后变成彩色, 然后将自己上下左右四 个方向相邻的方格触发染色。每个方格只能被触发染色一次, 第一次触发之后 的触发为无效触发。
给定每个方格的染色时间, 在时刻 0 触发第一行第一列的方格染色, 请问 多长时间后整个棋盘完成染色。
输入格式
输入的第一行包含两个整数 n,mn,m, 分别表示棋盘的行数和列数。
接下来 nn 行, 每行 mm 个正整数, 相邻的整数之间用一个空格分隔, 表示每 个方格的染色时间。该部分的第 ii 行第 jj 个整数表示 tijtij, 即第 ii 行第 jj 列的方 格的染色时间。
输出格式
输出一行包含一个整数, 表示整个棋盘完成染色的时间。
样例输入
2 3
1 2 3
4 5 6
样例输出
12
评测用例规模与约定
对于 3030 的评测用例, 1≤n,m≤101≤n,m≤10 。
对于 6060 的评测用例, 1≤n,m≤501≤n,m≤50 。
对于所有评测用例, 1≤n,m≤500,1≤tij≤10001≤n,m≤500,1≤tij≤1000 。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;
public class Main {
static int N=510;
static int n,m;
static int id=1;
static int cnt=-1;
static boolean f[][]=new boolean[N][N];//当前点是否已经被染色
static int a[][]=new int[N][N];
static int dist[][]=new int[N][N];
static int dx[]={0,-1,0,1};
static int dy[]={1,0,-1,0};
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
StringTokenizer st=new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
m=Integer.parseInt(st.nextToken());
for (int i = 1; i <= n; i++) {
st=new StringTokenizer(br.readLine());
for (int j = 1; j <= m; j++) {
a[i][j]=Integer.parseInt(st.nextToken());
}
}
int res=0;
//不可用BFS
PriorityQueue<int[]> queue=new PriorityQueue<>((a,b)->a[2]-b[2]);
queue.add(new int[]{1,1,a[1][1]});
for (int i = 0; i < N; i++) {
Arrays.fill(dist[i], Integer.MAX_VALUE);
}
dist[1][1]=a[1][1];
while(!queue.isEmpty()){
int no[]=queue.poll();
int x=no[0],y=no[1],cur=no[2];
if(!f[x][y]){
f[x][y]=true;
for (int i = 0; i < 4; i++) {
int nx=x+dx[i],ny=y+dy[i];
if(nx<1 || nx>n || ny<1 || ny>m)continue;
if(!f[nx][ny]){
if(cur+a[nx][ny]<dist[nx][ny]){
dist[nx][ny]=cur+a[nx][ny];
res=Math.max(res, dist[nx][ny]);
queue.add(new int[]{nx,ny,dist[nx][ny]});
}
}
}
}
}
bw.write(res+"");
br.close();
bw.flush();
bw.close();
}
}
小蓝组网
问题描述
给定一个含有 nn 个结点和 mm 条边的无向图,图中所有边的权值均为 11 ,且图中不包含重边。请判断该图中各点是否连通,并给出图中两个连通的点之间最短距离的最大值。
输入格式
输入第 11 行包括两个整数 n,mn,m ,分别表示图中结点的个数与边的个数。
第 2∼m+12∼m+1 行,每行包括两个整数 a,ba,b ,表示存在一条连接编号分别为 a,ba,b 的结点的无向边,结点编号范围从 11 到 nn 。
输出格式
输出两行,第 11 行判断图中各结点是否连通,若连通,则输出 YESYES ,否则输出 NONO 。 第 22 行输出两个连通的结点之间最短距离的最大值。
样例输入
5 4
1 2
2 3
3 4
4 5
样例输出
YES
4
说明
图中只有一个连通分量,必然是连通的,且两个连通的结点之间最短距离的最大值为 44 。
评测数据规模
对于 3030% 的评测数据,1≤n≤501≤n≤50, 1≤m≤1001≤m≤100 。
对于 5050% 的评测数据,1≤n≤2001≤n≤200, 1≤m≤100001≤m≤10000 。
对于 100100% 的评测数据,1≤n≤5001≤n≤500, 1≤m≤1051≤m≤105 。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.*;
public class Main {
static int N=510;
static int n,m;
static int id=1;
static int cnt=-1;
static int f[][]=new int[N][N];
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
StringTokenizer st=new StringTokenizer(br.readLine());
n=Integer.parseInt(st.nextToken());
m=Integer.parseInt(st.nextToken());
for (int i = 0; i < N; i++) {
Arrays.fill(f[i], Integer.MAX_VALUE);
f[i][i]=0;
}
for (int i = 0; i < m; i++) {
st=new StringTokenizer(br.readLine());
int a=Integer.parseInt(st.nextToken()),b=Integer.parseInt(st.nextToken());
f[a][b]=1;
f[b][a]=1;
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if(f[i][k]!=Integer.MAX_VALUE && f[k][j]!=Integer.MAX_VALUE){
f[i][j]=Math.min(f[i][j], f[i][k]+f[k][j]);
}
}
}
}
boolean connect=true;
int res=Integer.MIN_VALUE;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if(f[i][j]==Integer.MAX_VALUE)connect=false;
else res=Math.max(res, f[i][j]);
}
}
if(connect){
bw.write("YES\n");
}else{
bw.write("NO\n");
}
bw.write(res+"");
br.close();
bw.flush();
bw.close();
}
}