P3275 [SCOI2011] 糖果(差分约束)

P3275 [SCOI2011] 糖果

题目描述

幼儿园里有 N 个小朋友,lxhgww 老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww 需要满足小朋友们的 K 个要求。幼儿园的糖果总是有限的,lxhgww 想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

输入格式

输入的第一行是两个整数 NK。接下来 K 行,表示这些点需要满足的关系,每行 3 个数字,XAB

  • 如果 X=1, 表示第 A 个小朋友分到的糖果必须和第 B 个小朋友分到的糖果一样多;
  • 如果 X=2, 表示第 A 个小朋友分到的糖果必须少于第 B 个小朋友分到的糖果;
  • 如果 X=3, 表示第 A 个小朋友分到的糖果必须不少于第 B 个小朋友分到的糖果;
  • 如果 X=4, 表示第 A 个小朋友分到的糖果必须多于第 B 个小朋友分到的糖果;
  • 如果 X=5, 表示第 A 个小朋友分到的糖果必须不多于第 B 个小朋友分到的糖果;

输出格式

输出一行,表示 lxhgww 老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 1

输入输出样例 #1

输入 #1

5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1

输出 #1

11

说明/提示

对于 30% 的数据,保证 N100

对于 100% 的数据,保证 N100000

对于所有的数据,保证 K100000,1X5,1A,BN


upd 2022.7.6:新添加 21Hack 数据
这道题是一道典型的差分约束题,由于图不一定是连通的,所以我们需要建一个零点使他与所有点连接,边权为零,其次对于x=2和x=4时a和b肯定不能相等,所以我们可以在输入时就能直接得出答案,这样可以减少计算量,但我还是不能通过全部的hack

#include<iostream>
#include<queue>
#include<vector>
#define int long long
using namespace std;
char* p1, * p2, buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x = 0, f = 1;
    char ch = nc();
    while (ch < 48 || ch>57)
    {
        if (ch == '-')
            f = -1;
        ch = nc();
    }
    while (ch >= 48 && ch <= 57)
        x = x * 10 + ch - 48, ch = nc();
    return x * f;
}
const int N=1e6+10;
struct node{
int id,dis;
};
int cnt[N];
int vis[N];
vector<node>vc[N];
int w[N];
int n,k;
void spfa(){
    queue<int>q;
    for(int i=1;i<=n;i++){
        vc[0].push_back({i,0});
    }
    for(int i=0;i<=n;i++)w[i]=1e9;
    w[0]=0;
    for(int i=0;i<=n;i++)q.push(i),vis[i]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<vc[u].size();i++){
            int v=vc[u][i].id;
            if(w[u]+vc[u][i].dis<w[v]){
                w[v]=w[u]+vc[u][i].dis;
                cnt[v]=cnt[u]+1;
                if(cnt[v]>=n+1){
                    cout<<"-1";
                    return;
                }
                if(!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++)sum+=-w[i];
    cout<<sum+n;
}
signed main(){
    ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
    cin>>n>>k;
    while(k--){
        int x,a,b;
        cin>>x>>a>>b;
        if(x==1)vc[a].push_back({b,0}),vc[b].push_back({a,0});
        if(x==2){
            if(a==b){
                cout<<"-1";
                return 0;
            }
            vc[a].push_back({b,-1});
                }
        if(x==3)vc[b].push_back({a,0});
        if(x==4){
            if(a==b){
                cout<<"-1";
                return 0;
            }
            vc[b].push_back({a,-1});
                }
        if(x==5)vc[a].push_back({b,0});
    }
    spfa();
    return 0;
}

补:
双端队列优化,用别人博客的优化不行,用deepseek的就行,也不知道这是什么原理,出题人故意卡spfa真恶心

#include<iostream>
#include<queue>
#include<deque>
#include<vector>
#define int long long
using namespace std;
char* p1, * p2, buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x = 0, f = 1;
    char ch = nc();
    while (ch < 48 || ch>57)
    {
        if (ch == '-')
            f = -1;
        ch = nc();
    }
    while (ch >= 48 && ch <= 57)
        x = x * 10 + ch - 48, ch = nc();
    return x * f;
}
const int N=1e6+10;
struct node{
int id,dis;
};
int cnt[N];
int vis[N];
vector<node>vc[N];
int w[N];
int n,k;
void spfa(){
    deque<int>q;
    for(int i=1;i<=n;i++){
        vc[0].push_back({i,1});
    }
    for(int i=0;i<=n;i++)w[i]=-1e9;
    w[0]=0;
    for(int i=0;i<=n;i++)q.push_back(i),vis[i]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop_front();
        vis[u]=0;
        for(int i=0;i<vc[u].size();i++){
            int v=vc[u][i].id;
            if(w[u]+vc[u][i].dis>w[v]){
                w[v]=w[u]+vc[u][i].dis;
                cnt[v]=cnt[u]+1;
                if(cnt[v]>=n+1){
                    cout<<"-1";
                    return;
                }
                if(!vis[v]){
                    if(!q.empty()&&w[v]>w[q.front()]){
                        q.push_front(v);
                    }
                    else q.push_back(v);
                    vis[v]=1;
                }
            }
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++)sum+=w[i];
    cout<<sum;
}
signed main(){
    ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
    cin>>n>>k;
    while(k--){
        int x,a,b;
        cin>>x>>a>>b;
        if(x==1)vc[a].push_back({b,0}),vc[b].push_back({a,0});
        if(x==2){
            if(a==b){
                cout<<"-1";
                return 0;
            }
            vc[a].push_back({b,1});
                }
        if(x==3)vc[b].push_back({a,0});
        if(x==4){
            if(a==b){
                cout<<"-1";
                return 0;
            }
            vc[b].push_back({a,1});
                }
        if(x==5)vc[a].push_back({b,0});
    }
    spfa();
    return 0;
}
posted @   郭轩均  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示