题目
Description
已给定一个 N 个点 M条边的有向图,点编号为 1到N,第i 条边为(ui,vi) ,
权值为wi。你可以进行一次操作,使得任意一条边的权值变成任意非负整数。要
求进行尽量少的操作次数,使得点 1到点N 的最短路径长度变成c。
题目保证,c小于在未进行任何操作之前的原图中 1到N 的最短路长度。
Input
输入文件tweak.in 第一行三个整数,N,M和c
接下来M行,每行一条边的信息 ui,vi和wi,第i 行的表述第i 条边的信息。
保证不会有自环存在,对于不同的 i 和j, (ui,vi)不同于(uj,vj) 。
Output
输出文件 tweak.out 一行一个整数,要进行最少多少次操作才能使得最短路
长度变为c。
Sample Input
3 3 3 1 2 3 2 3 3 1 3 8
Sample Output
1
Data Constraint
Hint
将边 1,3的权值修改为 2就可以了。
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%数据满足M≤20
50%的数据满足 M≤70
分析
- 贪心水分??
- 暴力跟多一点??
- 拆点最短路(反正我不会)
- 还是老老实实DP
- 设f[i][j],表示从1出发到达节点i,用了j次修改的最小值
- 那么显然f[y][j]=f[x][j]+map[x][y] ,f[y][j+1]=f[x][j]
- 记得不能超出深度哦
代码
1 #include<iostream> 2 #include<vector> 3 #include<queue> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 vector<int> f[2001]; 8 int vis[2001]; 9 int n,m,c; 10 int a[2001]; 11 int map[2001][2001]; 12 int dp[2001][2001]; 13 int dis[2001]; 14 void spfa() 15 { 16 memset(dp,0x3f,sizeof(dp)); 17 dp[1][0]=0; 18 queue<int> q; 19 q.push(1); vis[1]=1; 20 while (!q.empty()) 21 { 22 int x=q.front(); q.pop(); vis[1]=0; 23 for (int i=0;i<f[x].size();i++) 24 { 25 int y=f[x][i]; 26 if (!vis[y]) 27 { 28 dis[y]=dis[x]+1; 29 vis[y]=1; 30 for (int i=0;i<=dis[x];i++) 31 dp[y][i]=min(dp[y][i],dp[x][i]+map[x][y]),dp[y][i+1]=min(dp[y][i+1],dp[x][i]); 32 q.push(y); 33 } 34 35 } 36 } 37 } 38 int main () 39 { 40 cin>>n>>m>>c; 41 for (int i=1,x,y,z;i<=m;i++) 42 { 43 cin>>x>>y>>z; 44 f[x].push_back(y); 45 map[x][y]=z; 46 } 47 spfa(); 48 for (int i=0;i<=m;i++) 49 if (dp[n][i]<=c) 50 { 51 cout<<i; 52 break; 53 } 54 }