1. 程式人生 > 實用技巧 >【Luogu T145192】 【2020.8.23NOIP模擬賽】最優路線

【Luogu T145192】 【2020.8.23NOIP模擬賽】最優路線

題目大意:

一個 \(n\) 個點 \(m\) 條邊的無重邊無自環的無向圖,點有點權,邊有邊權,定義一條路徑的權值為路徑經過的點權的最大值乘邊權最大值。求任意兩點間的權值最小的路徑的權值。

正文:

一道 Floyd 練手題,存下每條路的最大點權與邊權,在 Floyd 的時候一起運算,Floyd 時升序列舉點權作為中點。

程式碼:


int main()
{
	scanf ("%d%d", &n, &m);
	memset(mp, 0x7f, sizeof mp);
	memset(me, 0x7f, sizeof me);
	memset(dis, 0x7f, sizeof dis);
    for(int i = 1; i <= n; i++) 
		scanf("%d", &val[i]), a[i].val = val[i], a[i].id = i; 
    sort(a + 1, a + 1 + n, cmp); 
    for(int i = 1; i <= m; i++)
	{
        int u, v; ll w;
        scanf ("%d%d%lld", &u, &v, &w);
		me[u][v] = me[v][u] = w; 
        mp[u][v] = mp[v][u] = max(val[u], val[v]);
		vis[u][v] = vis[v][u] = 1;
		dis[u][v] = dis[v][u] = (ll)mp[v][u] * me[u][v]; 
    }
    for(int K = 1; K <= n; K++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
			{
                int k = a[K].id; 
                if(!vis[i][k] || !vis[k][j] || i == j) continue; 
                int maxp = max(mp[i][k], mp[k][j]),
				    maxe = max(me[i][k], me[k][j]); 
                if((ll)maxp * maxe < dis[i][j])
				{
                    dis[i][j] = (ll)maxp * maxe; 
                    mp[i][j] = maxp;
					me[i][j] = maxe; 
                    vis[i][j] = 1; 
                }
            }
    for(int i = 1; i <= n; i++)
	{
        for(int j = 1; j <= n; j++)
		{
            if(i == j) printf("0 ");
            else if(vis[i][j]) printf("%lld ", dis[i][j]);
            else printf("-1 ");
        }
        puts("");
    }
    return 0; 
 
}