专栏文章
题解:P4578 [FJOI2018] 所罗门王的宝藏
P4578题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mimyz9zo
- 此快照首次捕获于
- 2025/12/01 17:51 3 个月前
- 此快照最后确认于
- 2025/12/01 17:51 3 个月前
P4578 [FJOI2018] 所罗门王的宝藏 - 题解
前置知识
本题思路是将等式转化为两个不等式,进而使用差分约束算法,建议先复习一下P5960 【模板】差分约束。
题意
给定一个二维矩阵,矩阵中每个元素初始都是 。每次操作指定一行或一列,可以让对应行或列的元素都 ,或都 。矩阵中有一些位置为给定的密码元素,只有矩阵中所有的密码元素都正确,锁才会打开,问是否可能将锁打开。
分析
假设第 行的数值被增加了 次,第 行的数值被增加了 次,位置为 的密码值为 ,可以得到 ,此时使用差分约束,可以得到两个不等式:
但是由于这里均为加法,不好处理,于是改变定义,设第 行的数值被减小了 次,此时才得到了 ,转化为:
移项并整理,得到:
连边时要注意点的编号之间不冲突,不妨令 ,于是可以建图,,。
由于题目仅查询是否存在解,只需判断图中是否有负环,使用 SPFA 即可。
代码
CPP#include<bits/stdc++.h>
using namespace std;
const int N=4005;
int T,n,m,k,cnt[N],dis[N]; //注意存在j+n,所以要开两倍空间
bool vis[N];
vector<pair<int,int>> e[N];
bool spfa(int s){
queue<int> q;
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(auto i:e[u]){
int v=i.first,w=i.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
vis[v]=1;
cnt[v]++;
if(cnt[v]==n+m+1) return false; //这个点入队次数超过总点数,说明存在负环
q.push(v);
}
}
}
}
return true;
}
void init(){
e[0].clear();
for(int i=1;i<=n+m+1;i++){
e[i].clear();
e[0].push_back({i,0}); //设置超级源点
vis[i]=0;
cnt[i]=0;
}
}
int main(){
cin>>T;
while(T--){
cin>>n>>m>>k;
init(); //多测清空,注意SPFA中涉及的变量也要清空
for(int i=1;i<=k;i++){
int x,y,z;
cin>>x>>y>>z;
e[y+n].push_back({x,z}); //使用差分约束算法建边
e[x].push_back({y+n,-z});
}
if(spfa(0)) puts("Yes"); //从超级源点开始判断,保证图联通
else puts("No");
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...