题目
分析
- 我们要判断两点间是否相互连通
- 不单单只是两点能直接到达
- 间接到达也是可以的
- 所以我们跑一个Floyd
- 就能判断是否连通啦
- 然后要注意的一点是,我每一次跟新一次值都要放队列重新对其他点进行跟新
代码
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
int vis[201][201];
int dp[201][20];
int map[201][201];
int flag[201];
int fl[201][201];
int n,m,k;
vector<int> f[201];
void spfa()
{
memset(dp,0x3f,sizeof(dp));
queue<int> q; q.push(1);
dp[1][0]=0; flag[1]=1;
while (!q.empty())
{
int x=q.front(); q.pop(); flag[x]=0;
for (int i=0;i<f[x].size();i++)
{
int y=f[x][i];
if (fl[y][x]!=fl[0][0])
{
for (int j=0;j<=k;j++)
if(dp[x][j]+map[x][y]<dp[y][j])
{
dp[y][j]=min(dp[y][j],dp[x][j]+map[x][y]);
if(!flag[y])
{
flag[y]=1;
q.push(y);
}
}
}
else
{
for (int j=1;j<=k;j++)
if(dp[x][j-1]+map[x][y]*2<dp[y][j])
{
dp[y][j]=min(dp[x][j-1]+2*map[x][y],dp[y][j]);
if(!flag[y])
{
flag[y]=1;
q.push(y);
}
}
}
}
}
}
int main ()
{
cin>>n>>m>>k;
memset(map,0x3f,sizeof(map));
memset(fl,0x3f,sizeof(fl));
for (int i=1,x,y,z;i<=m;i++)
{
cin>>x>>y>>z;
if (!vis[x][y])
{
f[x].push_back(y);
vis[x][y]=1;
}
map[x][y]=min(map[x][y],z);
fl[x][y]=min(fl[x][y],z);
}
for (int kk=1;kk<=n;kk++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j&&i!=kk&&j!=kk&&fl[i][kk]+fl[kk][j]<fl[i][j])
fl[i][j]=fl[i][kk]+fl[kk][j];
spfa();
int ans=1e9;
for (int i=0;i<=k;i++)
ans=min(dp[n][i],ans);
if (ans==1000000000) cout<<-1;
else
cout<<ans;
}