您的位置:首页 > 其它

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

2016-11-25 22:12 155 查看

题目大意

给定一张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]

, maxi,maxk,n,m,ans;
int dist
,dist2
;
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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: