题面懒得复制,戳我戳我
Solution:
- 其实这个差分是挺显然的,我们可以用\(s[i]\)表示从第\(1\)到\(i\)中间的收入和
- 重点就在式子,比如读入\(a\),\(b\),\(c\),显然可以得到一个式子:$$s[b]-s[a-1]==c$$把这个式子变成不等式就是$$s[b]>=c+s[a-1]$$$$s[b]>=c+s[a-1]$$第二个式子又可以转换成$$s[a-1]<=-c+s[b]$$这就显然是从\(a-1\)连向\(b\)一条长度为\(c\)的边,从\(b\)连向\(a-1\)一条\(-c\)的边
- 然后我们就可以跑\(SPFA\)了,这有一点就是,因为要满足所有条件,每天的收入是固定的,我们就只用如下操作:更新至的点如果为\(INF\)(初值),就更新,否则判断是否符合边的条件要求\(s[v]==s[u]+dis[u,v]\)(u为出发点,v为到达点)
- 我傻逼的没有清空\(vis\)数组,WA了无数次(太愚蠢了)
Code:
//It is coded by Ning_Mew on 3.29
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000+10;
int T,n,m,INF;
int head[maxn],cnt=0,dist[maxn];
bool be[maxn];
struct Edge{int nxt,to,dis;}edge[maxn*2];
void add(int from,int to,int dis){
edge[++cnt].nxt=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
int vis[maxn];
bool SPFA(int k,int ls){
queue<int>Q;while(!Q.empty())Q.pop();
vis[k]=ls;Q.push(k);be[k]=false;
dist[k]=0;
while(!Q.empty()){
int u=Q.front();Q.pop();vis[u]=ls-1;
for(int i=head[u];i!=0;i=edge[i].nxt){
int v=edge[i].to;be[v]=false;
if(dist[v]==INF){
dist[v]=dist[u]+edge[i].dis;
if(vis[v]!=ls){
Q.push(v);
vis[v]=ls;
}
}
else{
if(dist[v]!=dist[u]+edge[i].dis)return false;
}
}
}return true;
}
void work(){
scanf("%d%d",&n,&m);
memset(head,0,sizeof(head));
memset(be,false,sizeof(be));cnt=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++){
int a,b,c;scanf("%d%d%d",&a,&b,&c);
add(a-1,b,c);be[a-1]=true;be[b]=true;
add(b,a-1,-1*c);
}
memset(dist,-0x5f,sizeof(dist));
INF=dist[0];
int ls=1;
for(int i=0;i<=n;i++){
if(be[i]==false)continue;
//cout<<i<<endl;
if(SPFA(i,++ls));else{
printf("false\n");
return;
}
}printf("true\n");
}
int main(){
scanf("%d",&T);
for(int i=1;i<=T;i++){work();}
return 0;
}