题目链接:点击打开链接
题意:
给定n个点m条有向边 常数c
下面m行给出边。
修改最少的边的边权使得1->n的最短路长度恰好为c(输入保证1->n存在最短路且最短路权值>c)
思路:
因为是DAG,而且c不大,所以应该是DAG上的dp,反向建边然后bfs出去。
dp[i][j]表示点i距离终点距离恰好为j时最少需要修改的边数。
初始状态为dp[n][0] = 0, 其他为inf。
从u转移到v,若边权不修改则:
1、dp[v][j+edge.dis] = min(dp[u][j]);
若修改这条边权则方程为:
2、dp[v][j] = min(dp[u][ j-? ] +1);
显然2的转移复杂度就是c*c,这样就太大了。
其实若把最短路修改为恰好为c 和 修改为<=c的答案是一样的,因为c越小答案应该越大,所以我们把题意转换成修改为<=c,
则ans = min(dp[n][ 0->c ])
这样2的方程就能改成dp[v][j] = min( dp[u][j]+1 );
O(1)的转移。
复杂度为O(m*c)
over.
#include <stdio.h>
#include <string.h>
#include <set>
#include <map>
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if (x>9) pt(x / 10);
putchar(x % 10 + '0');
}
using namespace std;
const int inf = 1e8;
const int N = 105;
const int M = 100010;
struct Edge{
int from, to, dis, nex;
}edge[1005];
int head[N], edgenum;
void add(int u, int v, int dis){
Edge E = { u, v, dis, head[u] };
edge[edgenum] = E;
head[u] = edgenum++;
}
void init(){ memset(head, -1, sizeof head); edgenum = 0; }
int n, m, c;
int dp[N][M], vis[N];
void bfs(){
queue<int>q;
q.push(n);
dp[n][0] = 0;
while (!q.empty()){
int u = q.front(); q.pop(); vis[u] = 0;
for (int i = head[u]; ~i; i = edge[i].nex){
int v = edge[i].to;
bool ok = false;
for (int j = 0; j <= c; j++)
{
if (dp[u][j] == inf)continue;
if (dp[v][j] > dp[u][j] + 1)
{
dp[v][j] = dp[u][j] + 1; ok = true;
}
if (j + edge[i].dis <= c && dp[v][j + edge[i].dis] > dp[u][j])
{
dp[v][j + edge[i].dis] = dp[u][j]; ok = true;
}
}
if (ok && vis[v] == 0)vis[v] = 1, q.push(v);
}
}
}
int main(){
int u, v, d;
while (cin>>n>>m>>c, n+m+c){
init();
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n; i++)for (int j = 0; j <= c; j++)dp[i][j] = inf;
while (m--)
{
rd(u); rd(v); rd(d);
add(v, u, d);
}
bfs();
int ans = inf;
for (int i = 0; i <= c; i++)ans = min(ans, dp[1][i]);
pt(ans); puts("");
}
return 0;
}
/*
3 3 3
1 2 10
1 2 5
2 3 3
4 5 3
1 2 10
1 2 5
2 3 3
3 4 1
4 2 6
4 5 1
1 2 10
1 2 5
2 3 3
3 4 1
4 2 6
4 5 8
1 2 10
1 2 5
2 3 3
3 4 1
4 2 6
4 5 0
1 2 10
1 2 5
2 3 3
3 4 1
4 2 6
*/