1. 程式人生 > 實用技巧 >查分約束的幾道簡單例題(糖果,layout,狡猾的商人,小k的農場)

查分約束的幾道簡單例題(糖果,layout,狡猾的商人,小k的農場)

糖果(SCOI2011, luoguP3275)

  輸入 
  5 7
  1 1 2
  2 3 2
  4 4 1
  3 4 5
  5 4 5
  2 3 5
  4 5 1
  輸出 
  11

簡單的解釋:

依然是分析建邊:

  • \(X=1\),有\(A=B\),因為我們要建立不等關係,所以轉化一下變成\(B>=A+0\)&&\(B>=A+0\),這裡因為要求最小值所以轉化為>=跑最長路。

  • \(X=2\),有\(A<B\),轉化得\(B>=A+1\)

  • \(X=3\),有\(A>=B\),轉化得\(A>=B+0\)(不要吐槽這是廢話qwq)

  • \(X=4\),有\(A>B\),轉化得\(A>=B+1\)

  • \(X=5\),有\(A<=B\),轉化得\(B>=A+0\)

因為要求分發的總量,搞一個超級源點向各點連邊,邊權為1,最後累加dis即可

PS:這道題有一個地方是第二條和第四條可以在讀入時直接判掉一部分非法情況,因為同一個人糖果數不可能不同。如果不這樣剪枝的會T掉兩個點,當然你也可以選擇最後0到各點加邊時倒著來,至於為什麼能行咱也不知道。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 100000 + 10;
#define ll long long
#define rint register int

int n, m, len = 0;
int head[maxn], dis[maxn], cnt[maxn];
bool vis[maxn];

struct edge{
	int nex, to, w;
}e[maxn << 2];

void Add(int u, int v, int w){
	e[++len].to = v;
	e[len].nex = head[u];
	e[len].w = w;
	head[u] = len;
}

bool Spfa(int u){
	queue<int> q;
	for(int i = 1; i <= n; i++)
		dis[i] = -1;
	dis[u] = 0;
	vis[u] = 1;
	q.push(u);
	while(!q.empty()){
		int x = q.front();q.pop();
		vis[x] = 0;
		for(rint i = head[x]; i; i = e[i].nex){
			int v = e[i].to;
			if(dis[v] < dis[x] + e[i].w){
				dis[v] = dis[x] + e[i].w;
				if(!vis[v]){
					if(++cnt[v] >= n) return 0;
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	return 1;
}

int main(){
	cin >> n >> m;
	int x, u, v;
	for(rint i = 1; i <= m; i++){
		scanf("%d %d %d", &x, &u, &v);
		if(x == 1) Add(u, v, 0), Add(v, u, 0);
		else if(x == 2){ 
			if(u == v){
				cout << -1 << endl;
				return 0;
			}
			Add(u, v, 1);
		}
		else if(x == 3) Add(v, u, 0);
		else if(x == 4) {
			if(u == v){
				cout << -1 << endl;
				return 0;
			}
			Add(v, u, 1);
		}
		else if(x == 5) Add(u, v, 0);
	}
	for(rint i = n; i >= 1; i--) Add(0, i, 1);//超級源點倒序加邊,為什麼會快呢
	if(!Spfa(0)) printf("-1\n");
	else{
		ll ans = 0;
		for(rint i = 1; i <= n; i++)
			ans += dis[i];
		cout << ans << endl;
	}
	return 0;
}

Layout

咱考試時的一道水題,明明第一遍敲對了最後還是腦抽改錯了,簡直。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
#define ll long long
const int maxn = 1000 + 10;
const int maxm = 5000 + 10;
struct node{
	int x, y, dis;
}a[5000<<2], b[5000<<2];

int head[maxn], len = 0, dis[maxn];
int n, M, K;

struct edge{
	int to, nex, w;
}e[maxm << 2];

void Add(int u, int v, int w){
	e[++len].to = v;
	e[len].nex = head[u];
	e[len].w = w;
	head[u] = len;
}

int cnt[maxn];
bool vis[maxn];

void Spfa(int u){
	queue<int> q;
	for(int i = 1; i <= n; i++)
		dis[i] = 0x3f3f3f3f;
	q.push(u);
	vis[u] = 1;
	dis[u] = 0;
	while(!q.empty()){
		int x = q.front(); q.pop();
		vis[x] = 0;
		for(int i = head[x]; i; i = e[i].nex){
			int v = e[i].to;
			if(dis[v] > dis[x] + e[i].w){
				dis[v] = dis[x] + e[i].w;
				if(!vis[v]){
					cnt[v]++;
					if(cnt[v] >= n){
						dis[n] = -1;
						return ;
					}
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
}

bool Cmp(node w, node p){
	return w.x == p.x ? w.y < p.x : w.x < p.x;
}

int main(){
	cin >> n >> M >> K;
	/*for(int i = 1; i <= M; i++)
		scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].dis);
	for(int i = 1; i <= K; i++)
		scanf("%d %d %d", &b[i].x, &b[i].y, &b[i].dis);
	sort(a + 1, a + 1 + M, Cmp);
	sort(b + 1, b + 1 + K, Cmp);*/
	int u, v, w;
	for(int i = 1; i <= M; i++){
		scanf("%d %d %d", &u, &v, &w);
		Add(u, v, w);
	}
	for(int i = 1; i <= K; i++){
		scanf("%d %d %d", &u, &v, &w);
		Add(v, u, -w);
	}
	for(int i = 1; i <= n; i++){
		Add(0, i, 0);
	}
	Spfa(0);
	if(dis[n] == -1){
		printf("-1\n");
		return 0;
	}
	Spfa(1);
	if(dis[n] == 0x3f3f3f3f){
		printf("-2\n");
		return 0;
	}
	printf("%d\n", dis[n]);
	return 0;
} 

狡猾的商人

我已經懶得粘題了qwq,傳送門:https://www.luogu.com.cn/problem/P2294

這道題要用到一點字首和的思想qwq,將\(U->V=C\)理解為\(sum[V]-sum[U-1]>=C\) && \(sum[U-1]-sum[V]>=C\),然後就是最長路板子了qwq

記得圖不一定連通,最後記得每個點都要跑一下。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define ll long long
#define inf 9999997
const int maxn = 100000 + 10;
inline int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}

struct edge{
	int nex, to, w;
}e[maxn << 2];

int n, m;
int head[maxn], len = 0;
int dis[maxn], cnt[maxn];
bool vis[maxn];

void Add(int u, int v, int w){
	e[++len].to = v;
	e[len].nex = head[u];
	e[len].w = w;
	head[u] = len;
}

bool Spfa(int s){
	queue<int> q;
	for(int i = 1; i <= n; i++) dis[i] = -inf;
	q.push(s);
	dis[s] = 0;
	vis[s] = 1;
	while(!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		cnt[u]++;
		if(cnt[u] >= n) return 0;
		for(int i = head[u]; i; i = e[i].nex){
			int v = e[i].to;
			if(dis[v] < dis[u] + e[i].w){
				dis[v] = dis[u] + e[i].w;
				if(!vis[v]){
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	return 1;
}

void Init(){
	memset(head, 0, sizeof head);
	memset(vis, 0, sizeof vis);
	memset(cnt, 0, sizeof cnt);
	len = 0;
}

int main(){
	int t = read();
	while(t--){
		Init(); 
		n = read(), m = read();
		int u, v, w;
		for(int i = 1; i <= m; i++){
			u = read(), v = read(), w = read();
			Add(v, u - 1, -w);
			Add(u - 1, v, w);
		}
		int flag = 1;
		for(int i = 0; i <= n; i++){
			if(!cnt[i]){
				if(!Spfa(i)){
					flag = 0;
					break;
				}
			}
		}
		if(flag) cout << "true" << endl;
		else cout << "false" << endl;
	}
	return 0;
}

小K的農場

傳送門:https://www.luogu.com.cn/problem/P1993

比前面的題都要裸的題qwq,直接看程式碼吧

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define ll long long
const int maxn = 10000 + 10;
inline int read(){
	int s = 0, w = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * w;
}

struct edge{
	int nex, to, w;
}e[maxn << 2];

int n, m;
int head[maxn], len = 0;
int dis[maxn], cnt[maxn];
bool vis[maxn];

void Add(int u, int v, int w){
	e[++len].to = v;
	e[len].nex = head[u];
	e[len].w = w;
	head[u] = len;
}

void Spfa(int u){
	queue<int> q;
	for(int i = 1; i <= n; i++)
		dis[i] = 0x3f3f3f3f;
	dis[u] = 0;
	vis[u] = 1;
	q.push(u);
	while(!q.empty()){
		int x = q.front();
		q.pop();
		vis[x] = 0;
		for(int i = head[x]; i; i = e[i].nex){
			int v = e[i].to;
			if(dis[v] > dis[x] + e[i].w){
				dis[v] = dis[x] + e[i].w;
				if(!vis[v]){
					if(++cnt[v] >= n){printf("No\n"); return ;}
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	printf("Yes\n");
	return ;
}

int main(){
	n = read(), m = read();
	int x, a, b, c;
	for(int i = 1; i <= m; i++){
		x = read();
		if(x == 1){
			a = read(); b = read(); c = read();
			Add(a, b, -c);
		}
		else if(x == 2){
			a = read(); b = read(); c = read();
			Add(b, a, c);
		}
		else{
			a = read(); b = read();
			Add(a, b, 0), Add(b, a, 0);
		}
	}
	for(int i = 1; i <= n; i++) Add(0 , i, 0);
	Spfa(0);
	return 0;
}