洛谷——P3275 [SCOI2011]糖果

P3275 [SCOI2011]糖果

差分约束模板题,基本思路就是$d[v]+w[v,u]<=d[u]$,$Spfa$更新方法,

有点套路的是要建立原点,即图中不存在的点来向每个点加边,但同样这是必须的,因为这样做是有意义的,每个小朋友必须要有一颗糖果

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>

#define N 10000000
using namespace std;

int n,k,tot,head[N];
long long ans;
struct node{
    int to,next,w;
}e[N];

void add(int u,int v,int w){
    e[++tot].to=v,e[tot].next=head[u],head[u]=tot,e[tot].w=w; 
}

int d[N],in[N];

struct npdE{
    int to,dis;
    bool operator < (npdE x)const{
        return dis>x.dis;
    }
};
queue<npdE>Q;
bool vis[N];

void spfa(){
    Q.push((npdE){0,0});
    vis[0]=1;
    while(!Q.empty()){
        int u=Q.front().to;vis[u]=0,Q.pop();
        if(in[u]>n) {
            printf("-1");return;
        } 
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(d[v]<d[u]+e[i].w){
                d[v]=d[u]+e[i].w;
                if(!vis[v]) in[v]=in[u]+1,vis[v]=1,Q.push((npdE){v,d[v]});
            }
        }
    }
    for(int i=1;i<=n;i++) ans+=d[i];
    printf("%lld
",ans); 
}

int main()
{
    scanf("%d%d",&n,&k);
    for(int x,u,v,i=1;i<=k;i++){
        scanf("%d%d%d",&x,&u,&v);
        if(x==1) add(u,v,0),add(v,u,0);
        else if(x==2) add(u,v,1);
        else if(x==3) add(v,u,0);
        else if(x==4) add(v,u,1);
        else add(u,v,0);
        if(x==2||x==4) if(u==v) {return puts("-1"),0;} 
    }
    for(int i=n;i>=1;i--) add(0,i,1);
    spfa();
    return 0;
}
原文地址:https://www.cnblogs.com/song-/p/9784329.html