FZOJ 4106 哈
一个图上的DP啊,怪我太年轻又没看出来考试的时候直接给它爆0了?
设\(f[i][j][k]\)表示从\(i\)点到\(j\)经过\(k\)条边。由于走过的边要求权值升序,不妨换个思路(不直接枚举状态),考虑直接把所有边从小到大排序然后直接枚举每条边,然后DP,注意因为要求的是经过 不多于 \(c\)条边的代价,而两点间的最短路径一定不会超过\(n\)条边所以枚举\(k\)的时候\(1-n\)就好了。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5009,INF=1<<30;
int n,m,q,f[151][151][151];
struct Edge
{
int x,y,z;
bool operator < (const Edge &A)const
{
return z<A.z;
}
}g[N];
void init()
{
scanf("%d %d %d",&n,&m,&q);
for (int i=1;i<=m;i++)
scanf("%d %d %d",&g[i].x,&g[i].y,&g[i].z);
sort(g+1,g+1+m);
}
void work()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=0;k<=n;k++)
f[i][j][k]=INF;
for (int i=1;i<=n;i++)
f[i][i][0]=0;
for (int i=0;i<=m;i++)
for (int j=1;j<=n;j++)
for (int k=0;k<n;k++)
if(f[j][g[i].x][k]!=INF)
f[j][g[i].y][k+1]=min(f[j][g[i].y][k+1],f[j][g[i].x][k]+g[i].z);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
f[i][j][k]=min(f[i][j][k-1],f[i][j][k]);
while(q--)
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
printf("%d\n",f[a][b][min(c,n)]==INF?-1:f[a][b][min(c,n)]);
}
}
int main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!