题目:gfoj---2017-07-03暑假训练题---行动!行动!
dp[i][j]表示从源点到第i座城市使用j个急救包的最小流血量。搜索到某个节点,如果dp[i][j+1]大于dp[father][j]则dp[i][j+1]=dp[father][j],然后需要对i节点使用j+1个急救包再进行松弛操作(spfa)。
dp初始值要很大很大很大很大
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
struct node
{
int y,wei;
};
const int maxSize=10000,maxValue=0x7fffffff;
vector <node> N[maxSize+5];
int vis[maxSize+5],f[maxSize+5][10+5];
int m,n,k,s,t;
queue <int> q;
void spfa()
{
int i,x,j;
node n1;
while (!q.empty())
{
x=q.front(); q.pop(); vis[x]=0;
for (i=0;i<N[x].size();i++)
{
n1=N[x][i];
for (j=0;j<=k;j++)
{
if (f[n1.y][j]>f[x][j]+n1.wei)//不用急救包
{
f[n1.y][j]=f[x][j]+n1.wei;
if (vis[n1.y]==0)
{
q.push(n1.y);
vis[n1.y]=1;
}
}
if (f[n1.y][j+1]>f[x][j] && j+1<=k && f[n1.y][j]>f[x][j])//用急救包
{
f[n1.y][j+1]=f[x][j];
if (vis[n1.y]==0)
{
q.push(n1.y);
vis[n1.y]=1;
}
}
}
}
}
}
int main()
{
int i,x,y,z,j,ans;
node n1;
freopen("a.txt","r",stdin);
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&s,&t);
for (i=0;i<m;i++)
{
scanf("%d%d%d",&x,&y,&z);
n1.y=y; n1.wei=z;
N[x].push_back(n1);
n1.y=x;
N[y].push_back(n1);
}
q.push(s);
memset(vis,0,sizeof(vis));
for (i=0;i<n;i++)
for (j=0;j<=k;j++)
f[i][j]=maxValue;
for (i=0;i<=k;i++)
f[s][i]=0;
vis[s]=1;
spfa();
ans=maxValue;
for (i=0;i<=k;i++)
ans=min(ans,f[t][i]);
printf("%d\n",ans);
return 0;
}