P1993 小 K 的农场 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
第一种:a-b>=c也就是b-a<=-c
第二种:b-a<=c
第三种:a=b
上面三种也就是差分约束,换种意思也就是:
一:b到a的距离为-c
二: b到a的距离为c
三:b到a的距离为0
使用bellmanford算法,若出现了负环我们就可以知道无法满足上面的这三种要求
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<bits/stdc++.h>
#include<cmath>
#include<cstring>
#include<iostream>
#include<map>
#include<queue>
#include<stdio.h>
#include<unordered_map>
#include<unordered_set>
#include<vector>
using namespace std;
typedef long long ll;
#define TT ll t;cin >> t;while (t--);
#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
const int N = 2e6 + 10;
struct node {
int ids, dis;
};
int n, m, a, b, c, w[N], f[N], cnt[N], t;
vector<node>arr[N];
int spfa() {
queue<int>q;
for (int i = 1; i <= n; i++)w[i] = 1e9, f[i] = 1, q.push(i);
w[1] = 0;
while (!q.empty()) {
int u = q.front(); q.pop();
f[u] = 0;
for (int i = 0; i < arr[u].size(); i++) {
int v = arr[u][i].ids;
int dis = w[u] + arr[u][i].dis;
if (dis >= w[v])continue;
w[v] = dis;
if (f[v])continue;
f[v] = 1;
q.push(v);
cnt[v]++;
if (cnt[v] >= n)return 0;
}
}
return 1;
}
void solve() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
cin >> t >> a >> b;
if (t == 3) {
arr[a].push_back({ b,0 });
arr[b].push_back({ a,0 });
}
else {
cin >> c;
if (t == 1)arr[b].push_back({ a,-c });
else {
arr[a].push_back({ b,c });
}
}
}
if (spfa())cout << "Yes\n";
else cout << "No\n";
return;
}
int main(){
IOS;
solve();
return 0;
}
P1119 灾后重建 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
用一个二维数组来存图即可,从第0号村庄开始,每重建一个村庄都要全部更新路径的长度(因为每通一个村庄,最短路径会发生改变),再判断两个村庄u,v此时的时间是否在允许的范围内,若在则输出最短路径,不在则输出-1
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<algorithm>
#include<bits/stdc++.h>
#include<cmath>
#include<cstring>
#include<iostream>
#include<map>
#include<queue>
#include<stdio.h>
#include<unordered_map>
#include<unordered_set>
#include<vector>
using namespace std;
typedef long long ll;
#define TT ll t;cin >> t;while (t--);
#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
const int N = 2e6 + 10;
ll t[N], a[210][210], u, v, w, n, m, q;
void floyed(int k) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
}
}
}
void solve() {
cin >> n >> m;
memset(a, 0x3f, sizeof(a));
for (int i = 0; i < n; i++)cin >> t[i];
for (int i = 0; i < m; i++) {
cin >> u >> v >> w;
a[u][v] = w;
a[v][u] = w;
}
for (int i = 0; i < n; i++)a[i][i] = 0;
cin >> q;
int i = 0;
t[n] = 1e9;
while (q--) {
cin >> u >> v >> w;
while (t[i] <= w)floyed(i++);
if (t[u] > w || t[v] > w || a[u][v] > 1e9) {
cout << "-1\n";
}
else {
cout << a[u][v] << "\n";
}
}
return;
}
int main(){
IOS;
solve();
return 0;
}
Educational Codeforces Round 170 (Rated for Div. 2)
思路:借鉴了jiangly大神的方法,感觉非常简便,题意是在一个数组中根据规则找到最大值(规则:第一次任意选一个数,从第二次开始每次选的数只能等于前一个数或比前一个数大1,这样的数最多不能超过k个)
代码:
void solve() {
ll n, k;
cin >> n >> k;
vector<ll>a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());//升序排序,从最小的开始
int ans = 0;
for (int i = 0, j = 0; i < n; i++) {
//1.确保不越界 2.保证符合规则 3.因为相邻的数最大差值为1,所以需要判断当前数和第一次的选定数之间的差值是否在k以内
while (j + 1 < n && a[j + 1] <= a[j] + 1 && a[j + 1] < a[i] + k) {
j++;
}
ans = max(j - i + 1, ans);//更新最大值,+1的原因是本身也算一次
}
cout << ans << "\n";
return;
}
https://codeforces.com/contest/2025/problem/B
思路:用错误的公式进行遍历之后可以发现规律,即每一次的输出都是pow(2,k[i])