[HNOI2005]狡猾的商人
题目大意:
n 个月,m 个约束条件,判断最终是否产生矛盾;
因为这里不是 x i x_i xi <= y j y_j yj + c k c_k ck,而是 s u m t sum_t sumt- s u m s − 1 sum_{s-1} sums−1 = v i v_i vi,所以单向连边并不满足条件,要正反双向连边,然后求最短路,判断是否有负环;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=20100;
const int M=50100;
const int mod=1e9;
int n,m;
struct Node{
int to,nex,w;
}edge[N*2];
int head[N],cnt,dis[N],vis[N],sum[N];
void add(int p,int q,int w){
edge[cnt].w=w,edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
bool spfa(){
for(int i=0;i<=n+1;i++) dis[i]=2e9,sum[i]=0,vis[i]=0;
dis[0]=0;
queue<int>qu;qu.push(0);
while(!qu.empty()){
int p=qu.front();qu.pop();
vis[p]=0;sum[p]++;
if(sum[p]>=n) return false;
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(dis[q]>dis[p]+edge[i].w){
dis[q]=dis[p]+edge[i].w;
if(!vis[q]) qu.push(q),vis[q]=1;
}
}
}
return true;
}
void init(){
memset(head,-1,sizeof(head));
cnt=0;
for(int i=0;i<=2*m;i++) edge[i].nex=edge[i].to=edge[i].w=0;
}
int main(){
int w;scanf("%d",&w);
while(w--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++){
int s,t,v;scanf("%d%d%d",&s,&t,&v);
add(s,t+1,v),add(t+1,s,-v);
}
for(int i=1;i<=n+1;i++) add(0,i,0);
if(!spfa()) printf("false\n");
else printf("true\n");
}
return 0;
}