题意
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;
}