洛谷 #3275. 糖果

题意

opt=1,表示第A个小朋友分到的糖果必须和第B个小朋友分到的糖果一样多
opt=2,表示第A个小朋友分到的糖果必须少于第B个小朋友分到的糖果
opt=3,表示第A个小朋友分到的糖果必须不少于第B个小朋友分到的糖果
opt=4,表示第A个小朋友分到的糖果必须多于第B个小朋友分到的糖果
opt=5,表示第A个小朋友分到的糖果必须不多于第B个小朋友分到的糖果
每个小朋友的糖果数>=1,问最小需要糖果数

题解

差分约束
opt=1:A到B连0边,B到A连0边
opt=2:A到B连1边
opt=3:B到A连0边
opt=1:B到A连1边
opt=1:A到B连0边
然后SPFA跑最长路

调试记录

建正权边要跑最长路
#include <cstdio>
#include <cstring>
#include <queue>
#include <cctype>
#define maxn 100005
#define int long long

using namespace std;

struct node{
	int to, next, l;
}e[maxn << 2];
int head[maxn], tot = 0;
void addedge(int u, int v, int l){
	e[++tot].to = v, e[tot].next = head[u], e[tot].l = l;
	head[u] = tot;
}

int n, k, dis[maxn], t[maxn];
bool inq[maxn];
bool SPFA(int s){
	dis[s] = 0; inq[s] = true;
	queue <int> q; while (!q.empty()) q.pop();
	q.push(s);
	while (!q.empty()){
		int cur = q.front(); q.pop(); inq[cur] = false;
		for (int i = head[cur]; i; i = e[i].next){
			if (dis[e[i].to] < dis[cur] + e[i].l){
				dis[e[i].to] = dis[cur] + e[i].l;
				if (!inq[e[i].to]){
					if (++t[e[i].to] >= n) return false;
					q.push(e[i].to);
					inq[e[i].to] = true;
				}
			}
		}
	}
	return true;
}

inline void read(int &x){
	x = 0; char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) x = (x * 10) + (ch & 15), ch = getchar();
}

signed main(){
	memset(dis, -0x3f, sizeof dis);
	read(n), read(k);
	for (int u, v, opt, i = 1; i <= k; i++){
		read(opt), read(u), read(v);
		if (opt == 1) addedge(u, v, 0), addedge(v, u, 0);
		if (opt == 2){
			if (u == v){
				puts("-1");
				return 0;
			}
			addedge(u, v, 1);
		}
		if (opt == 3) addedge(v, u, 0);
		if (opt == 4){
			if (u == v){
				puts("-1");
				return 0;
			}
			addedge(v, u, 1);
		}
		if (opt == 5) addedge(u, v, 0);
	}
	for (int i = n; i >= 1; i--) addedge(0, i, 1);
	if (!SPFA(0)) puts("-1");
	else{
		int res = 0;
		for (int i = 1; i <= n; i++) res += dis[i];
		printf("%d\n", res);
	}
	
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值