codevs 3983 调整(tweak)

本文介绍了一种针对有向图的最短路径优化算法,旨在通过调整边的权重来减少从起点到终点的最短路径长度。算法通过动态规划方法求解最少调整次数,使得最短路径长度达到指定目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述 Description
已给定一个N个点M条边的有向图,点编号为1到N,第i条边为 (ui,vi), 权值为wi。你可以进行一次操作,使得任意条边的权值变成非负整数。要求进行尽量少的操作次数,使得点1到点N的最短路径长度变成c
题目保证,c小于在未进行任何操作之前的原图中1到N的最短路长度。

输入描述 Input Description
输入文件tweak.in。
第一行三个整数,NMc
接下来M行,每一条边的信息uiviwi,第i行的表述第i条边的信息。 保证不会有自环存在,对于不同的ij(ui,vi)不同于(uj,vj)

输出描述 Output Description
输出文件 tweak.out。
一行一个整数,要进行最少多少次操作才能使得最短路长度变为c

样例输入 Sample Input
3 3 3
1 2 3
2 3 3
1 3 8

样例输出 Sample Output
1

数据范围及提示 Data Size & Hint
N<=100
M<=1000
0<=c<=100000
0<=wi<=10000
30%数据满足 M<=20
50%数据满足 M<=70

思路
显然每次调整都可以视为是把每条边变为0,最终距离小于等于c都算可行解。
fi,j,k表示ij,将k条边变为0后所得到的最短路长度。那么:

fi,j,0=min(disti,j,fi,k,0+fk,j,0)(1<=k<=n)

fi,j,p=min(fi,x,p1,fi,k,p+fk,j,0)(1<=k<=n,1<=x<=n,xj)

最终输出时输出满足f1,n,i<=c的最小的i

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

const int maxn=100;
const int inf=0x3f3f3f3f;

int n,m,c,dist[maxn+1][maxn+1];
int f[maxn+1][maxn+1][maxn+1];

int main()
{
    memset(dist,63,sizeof dist);
    memset(f,63,sizeof f);
    scanf("%d%d%d",&n,&m,&c);
    for(int i=1; i<=n; i++)
    {
        dist[i][i]=0;
        f[i][i][0]=0;
    }
    for(int i=1; i<=m; i++)
    {
        int a,b,v;
        scanf("%d%d%d",&a,&b,&v);
        dist[a][b]=v;
        f[a][b][0]=std::min(f[a][b][0],dist[a][b]);
    }
    for(int k=1; k<=n; k++)
    {
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                f[i][j][0]=std::min(f[i][j][0],f[i][k][0]+f[k][j][0]);
                for(int p=1; p<=n; p++)
                {
                    if(dist[k][j]!=inf)
                    {
                        f[i][j][p]=std::min(f[i][j][p],f[i][k][p-1]);
                    }
                    f[i][j][p]=std::min(f[i][j][p],f[i][k][p]+f[k][j][0]);
                }
            }
        }
    }
    for(int i=0; i<=n; i++)
    {
        if(f[1][n][i]<=c)
        {
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值