zoukankan      html  css  js  c++  java
  • Luogu P1613 跑路

    题目用倍增进行确定路径, Floyd来找到答案。

    用一个三元数组f[i][j[k], i 与 j 表示从点i到点j,k表示这条路的长度为2 ^ k,当f[i][j][k] = 1时表示存在这样一条路,反正则无。 这样预处理后,跑一次Floyd就可以得出答案。

    有一点需要注意,题目中m <= 10000, 而2的14次方已经大于10000,但在倍增时外循环的值k却要大于14才能AC此题的原因是如图

    我们可以发现把那个环跑两次就可以得到16的路程得到答案1,这时2 ^ 4大于边数10.所以由此可以推理当把环的长度变大时可能可以凑出一个k,这时2 ^ k 远大于10000.

    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    const int inf = 777777;
    
    int n, m;
    int f[51][51][50], ans[51][51];
    
    template<typename T>
    inline void read(T &x){
    	x = 0;
    	T op = 1;
    	char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar())
    		if(c == '-')	op = -1;
    	for(; c <= '9' && c >= '0'; c = getchar())
    		x = (x << 3) + (x << 1) + c - '0';
    	x *= op; 
    } 
    
    int main(){
    	read(n), read(m);
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= n; ++j){
    			if(i != j)	ans[i][j] = inf;
    			else ans[i][j] = 0;
    		}
    	for(int i = 1; i <= m; ++i){
    		int x, y;
    		read(x), read(y);
    		f[x][y][0] = 1;
    		if(x != y) ans[x][y] = 1;	
    	}
    	for(int k = 1; k < 50; ++k)
    		for(int v = 1; v <= n; ++v)
    			for(int i = 1; i <= n; ++i)
    				for(int j = 1; j <= n; ++j)
    					if(f[i][v][k - 1] && f[v][j][k - 1]){
    						f[i][j][k] = 1;
    						if(i != j) ans[i][j] = 1;
    					}
    	for(int k = 1; k <= n; ++k)
    		for(int i = 1; i <= n; ++i)
    			for(int j = 1; j <= n; ++j)
    				ans[i][j] = min(ans[i][j], ans[i][k] + ans[k][j]);
    	printf("%d
    ", ans[1][n]);
    	return 0;
    }
    
  • 相关阅读:
    How Default Heap Of Process Grows
    希腊字母表
    Ubuntu第一次亲密接触
    Ubuntu中的挂载点(mount point)
    要一专多能
    First touch with JIT debugging
    小学一下环境变量
    安装VMware Tools
    [转]ReiserFS与ext3的比较
    [bbk4485]第二章Flashback Database 05
  • 原文地址:https://www.cnblogs.com/ZmeetL/p/11801188.html
Copyright © 2011-2022 走看看