一些做题记录
图论
P1993 小 K 的农场
复习差分约束QAQ。设农场 种植的作文有 个单位,则题目中的三个条件就是:
其中第一个不等式可以转化成
注意到最短路中对于任何节点 ,都满足 ,所以我们只需要对于不等式一,从 向 连一条长度为 的边,对于不等式二,从 向 连一条长度为 的边,对于不等式三,因为 且 ,所以我们从 向 连一条长度为 的边,再从 向 连一条长度为 的边,最后跑一遍最短路即可。需要注意,有可能图中出现负环,判无解即可。
#include<bits/stdc++.h>
using namespace std;
#define N 6010
#define pii pair<int, int>
int n, m;
int vis[N], cnt[N], d[N];
vector<pii> e[N];
int spfa(int s){
queue<pii> q;
q.push({s, 0});
memset(d, 0x3f, sizeof d);
vis[s] = 1, d[s] = 0;
while(!q.empty()){
int u = q.front().first; q.pop();
vis[u] = 0;
for(auto v : e[u]){
if(d[v.first] > d[u] + v.second){
d[v.first] = d[u] + v.second;
cnt[v.first] = cnt[u] + 1;
if(cnt[v.first] >= 2 * n) return 0;
if(!vis[v.first]){
vis[v.first] = 1;
q.push({v.first, d[v.first]});
}
}
}
}
return 1;
}
signed main(){
// freopen("sr.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
while(m--){
int op, a, b, c;
cin >> op >> a >> b;
if(op == 1){
cin >> c;
e[a].push_back({b, -c});
}
else if(op == 2){
cin >> c;
e[b].push_back({a, c});
}
else{
e[a].push_back({b, 0}), e[b].push_back({a, 0});
}
}
for(int i = 1; i <= n; i ++){
e[n + 1].push_back({i, 0});
}
if(spfa(n + 1)) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
P1195 口袋的天空
一眼最小生成树。但是题意仍然看了好久才看懂QAQ。就是给定 个点, 条边,连成 个树的最小代价。容易想到 Kruskal,每一次建边将当前的连通块--,直到最后为 个即可。感觉Prim没什么应用场景啊 。
#include<bits/stdc++.h>
using namespace std;
#define N 1010
#define M 10010
int n, m, k;
int cnt, ans;
int fa[N];
struct EDGE{
int a, b, w;
}e[M];
int find(int x){
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int cmp(EDGE a, EDGE b){
return a.w < b.w;
}
signed main(){
// freopen("sr.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= m; i ++){
int a, b, c;
cin >> a >> b >> c;
e[i] = {a, b, c};
}
for(int i = 1; i <= n; i ++){
fa[i] = i;
}
cnt = n;
sort(e + 1, e + m + 1, cmp);
for(int i = 1; i <= m; i ++){
int a = find(e[i].a), b = find(e[i].b);
if(a == b) continue;
cnt--;
fa[a] = b;
ans += e[i].w;
if(cnt == k){
cout << ans;
return 0;
}
}
cout << "No Answer";
return 0;
}
P1550 [USACO08OCT] Watering Hole G
感觉很奇妙的一题。看似图中只有 个节点,实际上,完全可以将打井看作是向地下的某个隐藏节点连边。于是就加上这个节点跑最小生成树就好啦。
我才不会说我写Kruskal忘排序了呢
#include<bits/stdc++.h>
using namespace std;
#define N 310
#define M 100010
int n, m;
int cnt = 0;
int p[N];
struct EDGE{
int a, b, w;
}e[M];
int find(int x){
return p[x] == x ? x : p[x] = find(p[x]);
}
int cmp(EDGE a, EDGE b){
return a.w < b.w;
}
void Kruskal(){
sort(e + 1, e + cnt + 1, cmp);
int ans = 0;
for(int i = 1; i <= n + 1; i ++) p[i] = i;
for(int i = 1; i <= cnt; i ++){
int a = find(e[i].a), b = find(e[i].b);
if(a == b) continue;
ans += e[i].w;
p[a] = b;
}
cout << ans;
}
signed main(){
//freopen("sr.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++){
int w;
cin >> w;
e[++cnt] = {n + 1, i, w};
}
for(int i = 1; i <= n ;i ++){
for(int j = 1; j <= n; j ++){
int w;
cin >> w;
e[++cnt] = {i, j, w};
}
}
Kruskal();
return 0;
}
本文作者:星影流灿
本文链接:https://www.cnblogs.com/yduck/p/18353098
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步