UESTC Training for Graph Theory H 差分约束基础题

H - 咸鱼睡觉觉
原题地址
大概题意:emmmmm…… 直接看题:

就是在 ai ~bi 间去除ci 只咕咕,问最少的咕咕数。

思路分析:涉及到区间,线段树?还是分块?貌似都不好解决。那么如何去做?差分约束。
简单说明一下,首先用 sum[ i ]表示区间的前缀和,那么 sum[ b ]-sum[ a-1 ]就是区间[ a,b ]的和,再看题目的约束条件:
sum[ bi ]-sum[ ai-1 ]>=ci ,除此之外,还有隐含条件:
0<=sum[ i ]-sum[ i-1 ]<=1; 那么这两个可以拆成3个不等式,我们可以想到什么?最短路的松弛操作。想一下,我们构建最短路的时候:dis[ v ]<=dis[ u ]+w[ u ][ v ],那么就是
dis[ u ]-dis[ v ]>= - w[ u ][ v ]. 所以总结就是求一下最短路即可。

核心代码:
1.

初始化,定义边结构体。这里用了前向星存储边。不再赘述。
2.

Spfa 求最短路。这里注意几点:这里的松弛操作就是不等式的转化;最后返回的是 -dis[ 0 ],因为我们改变不等式后路径上的权值之和是 -∑w ,而我们求的是 ∑w ,所以最后应该是 - dis[ 0 ]。

#include<bits/stdc++.h>
using namespace std;
 typedef long long ll;
 #define inf 0x3f3f3f3f
struct Edge
{
    int to;
    int next;
    int w;
}edge[500050];

int edgecount;
int head[50050];
int dis[50050];
bool vis[50050];
void init()
{
    memset(head,-1,sizeof(head));
    edgecount=0;
}
 void add(int u,int v,int w)
 {
     edge[++edgecount].to=v;
     edge[edgecount].w=w;
     edge[edgecount].next=head[u];
     head[u]=edgecount;
 }
 void spfa(int n)
 {
     memset(vis,0,sizeof(vis));
     for(int i=0;i<=n;i++)dis[i]=inf;
      dis[n]=0;
     vis[n]=1;
     queue<int> q;
     q.push(n);
     int cnt=1;
     while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int k=head[u];k!=-1;k=edge[k].next){
            int t=dis[u]+edge[k].w;
            if(dis[edge[k].to]>t){
                dis[edge[k].to]=t;
                if(vis[edge[k].to])continue;
                q.push(edge[k].to);
                vis[edge[k].to]=1;
            }
        }
        vis[u]=0;
     }
     cout<<-dis[0]<<endl;
 }

int main()
{
    int n,k;
    scanf("%d%d",&k,&n);
    int a,b,c;
    init();
    int maxn=0;
    for(int i=1;i<=n;i++){
        scanf("%d%d%d",&a,&b,&c);
        a++,b++;
        maxn=max(maxn,b);
        add(b,a-1,-c);
    }
    for(int i=1;i<=maxn;i++){
        add(i,i-1,0);
        add(i-1,i,1);
    }
    spfa(maxn);
}

猜你喜欢

转载自blog.csdn.net/qq_40273481/article/details/80862151