• 洛谷 P3275 [SCOI2011]糖果(差分约束,tarjan强连通分量,scc)


    [SCOI2011]糖果

    题目描述

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

    输入格式

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

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

    输出格式

    输出一行,表示 lxhgww \text{lxhgww} lxhgww 老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 − 1 -1 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    样例输出 #1

    11
    
    • 1

    提示

    对于 30 % 30\% 30% 的数据,保证 N ≤ 100 N\leq100 N100

    对于 100 % 100\% 100% 的数据,保证 N ≤ 100000 N\leq100000 N100000

    对于所有的数据,保证 K ≤ 100000 , 1 ≤ X ≤ 5 , 1 ≤ A , B ≤ N K\leq100000, 1\leq X\leq5, 1\leq A, B\leq N K100000,1X5,1A,BN


    upd 2022.7.6 \text{upd 2022.7.6} upd 2022.7.6:新添加 21 21 21Hack 数据

    1、 这题是差分约束,最小化某两个变量的距离。
    	对于约束条件 x[i]-x[j]<=w,转化为x[j]>=x[i]-w;
    	类比单源最长路径中的三角不等式 (d[v]>=d[u]+w, u->v),
    	连 i->j 边权=-w的边,代表d[j]不能小于d[i]+w
    	
    2、如果图中没有 正环, 说明有解。
    3、如果用 spfa 求最长距离,这里会TLE.
    4、但是它边权只有 00 或 11,考虑这个图有什么特殊性质。
    	先缩点,每个 SCC 内部如果出现了一条 uu 到 vv 的边权为 11,根据 SCC 的定义,
    	一定还存在一条 vv 到 uu 的路径,由于边权 \geq 0≥0,所以一定会出现一个正权环,
    	则这个差分约束系统无解。否则的话,发现 SCC 内部变量取值一定是相同的,
    	那么问题变成了一个 DAG 上最长路,拓扑排序即可	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    #include 
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 10, M = 2e5 + 10;;
    const int inf = 0x3f3f3f3f;
    int head[N], ver[M], edge[M], Next[M];
    int head1[N], ver1[M], edge1[M], Next1[M];
    int n, m, tot, tot1;
    
    int stk[N], instk[N], top;	//栈
    int dfn[N], low[N], num;
    int scc[N], siz[N], cnt;
    int in_degree[N];	//缩点的入度
    int dis[N];			//缩点后的图,到某一点路径上,所有点权值的最大值
    
    
    void add(int x, int y, int z)
    {
    	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;	
    }
    
    void add1(int x, int y, int z)	//缩点重新就建图
    {
    	ver1[++tot1] = y, edge1[tot1] = z, Next1[tot1] = head1[x], head1[x] = tot1;	
    }
    
    void tarjan(int x)
    {
    	dfn[x] = low[x] = ++num;
    	stk[++top] = x, instk[x] = 1;
    	for(int i = head[x]; i; i = Next[i])
    	{
    		int y = ver[i];
    		if(!dfn[y])	//y尚未访问
    		{
    			tarjan(y);
    			low[x] = min(low[x], low[y]);
    		}else if(instk[y]){	//y已经访问并且在栈中
    			low[x] = min(low[x], dfn[y]);
    		}
    	}
    	//离x时, 记录scc
    	if(dfn[x] == low[x]) // 若x是scc的根
    	{
    		int y; ++cnt;
    		do{
    			y = stk[top--]; instk[y] = 0;
    			scc[y] = cnt; // scc编号
    			++siz[cnt];
    		}while(y != x);
    	}
    }
    
    void bfs()
    {
    	queue<int> q;
    	for(int i = 1; i <= cnt; ++i)
    	{
    		if(in_degree[i] == 0)
    		{
    			q.push(i);
    			dis[i] = 1;
    		}
    	}
    	while(q.size())
    	{
    		int x = q.front(); q.pop();
    		for(int i = head1[x]; i; i = Next1[i])
    		{
    			int y = ver1[i], z = edge1[i];
    			if(dis[y] < dis[x] + z)
    			{
    				dis[y] = dis[x] + z;
    			}
    			in_degree[y]--;
    			if(in_degree[y] == 0)
    				q.push(y);
    		}
    	}
    	ll ans = 0;
    	for(int i = 1; i <= cnt; ++i)
    	{
    	//	printf("dis[%d] = %d, siz[%d] = %d\n", i, dis[i], i, siz[i]);
    		ans += (ll)siz[i] * dis[i];
    	}
    	printf("%lld\n", ans);
    }
    
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	int op, x, y;
    	for(int i = 0; i < m; ++i)
    	{
    		scanf("%d%d%d", &op, &x, &y);
    		if(op == 1){
    			add(x, y, 0), add(y, x, 0);	
    		}else if(op == 2){
    			add(x, y, 1);
    		}else if(op == 3){
    			add(y, x, 0);	
    		}else if(op == 4){
    			add(y, x, 1);
    		}else{
    			add(x, y, 0);
    		}
    	}
    	for(int i = 1; i <= n; ++i)
    	{
    		if(!dfn[i])
    			tarjan(i);
    	}
    	bool flag = false;
    	for(int x = 1; x <= n; ++x)
    	{
    		for(int i = head[x]; i; i = Next[i])
    		{
    			int y = ver[i], z = edge[i];
    			if(scc[x] != scc[y])
    			{
    				add1(scc[x], scc[y], z);
    				in_degree[scc[y]]++;
    			}else{
    				if(z != 0)
    				{
    					flag = true;
    					break;
    				}
    			}
    		}
    	}
    	if(flag)
    	{
    		printf("-1\n");
    		return 0;
    	}
    	bfs();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
  • 相关阅读:
    【KBQA综述-0】Complex Knowledge Base Question Answering: A Survey
    零基础学Java(11)自定义类
    国外访问学者/博士后留学人员反诈骗指南
    BBR 数学模型直观展示
    【计算机视觉 | 图像模型】常见的计算机视觉 image model(CNNs & Transformers) 的介绍合集(二)
    java - 集合
    Oracle(55)什么是并行查询(Parallel Query)?
    Node.js 实战 第2章 Node 编程基础 2.1 Node 功能的组织及重用
    女鹅冬天的第一件羽绒服,当然要时尚经典的
    【趣话计算机底层技术】一个故事看懂各种锁
  • 原文地址:https://blog.csdn.net/qq_38232157/article/details/127947272