P1260 工程规划

差分约束板子

差分约束:把 i - j >= x 操作等价于从 j 到 i 连一条边权为 x 的边。然后跑一遍spfa统计最短路,即为一组合法序列。

这道题里要求以一个点为基准点 0 ,在跑完spfa之后统计最小的dis值,然后按顺序输出dis值减去这个最小值即可。

另一个问题是图不一定连通,有两个解决方法:

1.建一个万能点与所有的点相连,当然边权都是0.

2.跑spfa的时候要记录每个点的弹出次数,因此遍历一遍点,弹出次数为0就spfa,否则continue

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,h[2005]={},dis[2005]={},cnt=0,minn,que[1000500]={},times[2005]={},head,tail;
bool vis[2005]={};
struct Edge
{
    int to,next,w;
}e[10005];
void add(int u,int v,int w)
{
    e[++cnt]=(Edge){v,h[u],w};
    h[u]=cnt;
}
void spfa(int st)
{
    head=0;
    tail=1;
    dis[st]=0;
    que[1]=st;
    times[st]++;
    while(head<tail)
    {
        int u=que[++head];
        vis[u]=0;
        for(int i=h[u];i+1;i=e[i].next)
        {
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    times[v]++;
                    if(times[u]>=n) 
                    {
                        printf("NO SOLUTION\n");
                        exit(0);
                    }
                    que[++tail]=v;
                }
            }
        }
    }
    vis[st]=0;
}
int main()
{
    memset(h,-1,sizeof(h));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(v,u,w);
    }
    for(int i=1;i<=n;i++)
        dis[i]=214748364;
    for(int i=1;i<=n;i++)
    {
        if(times[i]) 
            continue;
        spfa(i);
    }
        minn=999999999;
        for(int i=1;i<=n;i++) 
            minn=min(minn,dis[i]);
        for(int i=1;i<=n;i++)     
            printf("%d\n",dis[i]-minn);
    return 0;
}

 

转载于:https://www.cnblogs.com/charlesss/p/10534168.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值