hiho一下 第110周 floyd + 貪心 + 倍增

題目大意

給定一張N個點的完全圖,可以從任何一個點出發,同一個點可以經過多次。詢問總路徑長度不超過M的情況下,最多能夠經過多少個點。

 

輸入是 n和m

以及一個n*n的矩陣,mp[i][j]表示點i到點j的距離

 

把初始矩陣的點理解爲從點i出發,經過一條邊後,最後停在點j的距離.

我們可以發現,這個矩陣A和B相乘之後,得到的矩陣的mp[i][j]的意義爲從i出發 ,經過A+B條邊之後停留在j的距離

 

因此我們可以倍增地算出所有mp[k][i][j] ,k爲2的倍數,通過類此flody的思想,logm*n^3的複雜度預處理出所有的mp

 

之後,我們要選的路徑長度不超過m的最多經過的點數,這個方案,必然是若干個上述矩陣的乘積的結果。

 

顯然,經過二進制拆分後,不可能存在這樣的情況:在某一步,選擇一個較小的矩陣會比選一個大的矩陣更優,因爲顯然如果可以選大的就直接選大的,比該矩陣小的所有矩陣加起來的收益還不如一個大的 (2^k>  1+ 2 +4 +8 +.....+2^(k-1 ) )

因此從大到小貪心即可

 

代碼參考自:

http://www.bubuko.com/infodetail-1743228.html

 

.

#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
#define inf 0x3f3f3f3f

const int N=150;
int mp[40][N][N], maxi,maxk,n,m,ans;
int dist[N],dist2[N];
int main()
{
    memset(mp,inf,sizeof mp);
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            scanf("%d",&mp[0][i][j]);

    for(int i=0; i<n; i++) mp[0][i][i]=inf; //根據題意,不能停留,因此設距離到自己爲inf

    for(int i=2,k=1; i<=m; i<<=1,k++)
    {
        maxi=i,maxk=k;
        for(int x=0; x<n; x++)
            for(int y=0; y<n; y++)
                for(int z=0; z<n; z++)
                    mp[k][y][z]=min(mp[k][y][z],mp[k-1][y][x]+mp[k-1][x][z]);
    }
    int ans=0;
//    cout<<maxi<<" "<<maxk<<endl;
    for(int i=maxi,k=maxk; i; i>>=1,k--)
    {
        int flag=0;
        for(int j=0; j<n; j++) dist[j]=inf;
        for(int x=0; x<n; x++)
            for(int y=0; y<n; y++)
            {
                if (dist[y]>dist2[x]+mp[k][x][y])
                {
                    dist[y]=dist2[x]+mp[k][x][y];
                    if (dist[y]<=m) flag=1;
                }
            }
        if (flag)
        {
            ans+=i;
            memcpy(dist2,dist,(n+5)*sizeof (int));
        }
    }
    printf("%d\n",ans);



    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章