• 【题解】狡猾的商人


    一道有意思的差分约束,涨知识了。

    题目地址:(luogu) (P2294)

    看到这道题是不是感觉与差分约束一点关系没有啊。

    分析一下从(s)月到(t)月的收入为(c)这句话。

    注意是收入,它有累加的性质。也就是说:

    (sum[t]-sum[s-1]=c),即前缀和。

    那么我们如果以这一条为约束条件建图,就会发现一个差分约束的雏形。但是我们发现,这样是错的。

    因为我们的约束条件不够。

    从等式性质来看,显然还需要满足:(sum_{s-1}-sum_t=-c)

    再建一条边即可。

    继续考虑细节:起点从哪里来呢?

    不用多想,图不一定连通的话,暴力遍历一遍所有点,对于没有访问过的点,再跑一遍(Spfa)即可。

    (Code:)

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int MAXN=500000;
    #define inf 0x3f
    int T,n,m,head[MAXN],dis[MAXN],tot;
    int vis[MAXN],cnt[MAXN],F=0;
    queue<int>q;
    struct edge{
    	int nxt,to,dis;
    }e[MAXN];
    inline void add(int x,int y,int w){
    	e[++tot].nxt=head[x];
    	e[tot].to=y;
    	e[tot].dis=w;
    	head[x]=tot;
    }
    bool SPFA(int s){
    	memset(dis,-inf,sizeof(dis));
    	dis[s]=0,q.push(s),vis[s]=1;
    	while(!q.empty()){
    		int k=q.front();
    		q.pop();vis[k]=0;
    		cnt[k]++;
    		if(cnt[k]>=n)return 0;
    		for(int i=head[k];i;i=e[i].nxt){
    			int j=e[i].to;
    			if(dis[j]<dis[k]+e[i].dis){
    				dis[j]=dis[k]+e[i].dis;
    				if(!vis[j])vis[j]=1,q.push(j);
    			}
    		}
    	}
    	return 1;
    }
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		F=0;
    		scanf("%d%d",&n,&m);
    		memset(head,0,sizeof(head));
    		tot=0;memset(cnt,0,sizeof(cnt));
    		memset(vis,0,sizeof(vis));
    		for(int i=1;i<=m;++i){
    			int a,b,c;
    			scanf("%d%d%d",&a,&b,&c);
    			//sum[b]-sum[a-1]=c,sum[a-1]-sum[b]=-c
    			add(a-1,b,c);add(b,a-1,-c);
    		}
    		for(int i=0;i<=n;++i)
    			if(!cnt[i])
    				if(!SPFA(i)){
    					F=1;
    					break;
    				}
    		if(!F)printf("true
    ");
    		else printf("false
    ");
    	}
    	return 0;
    } 
    
  • 相关阅读:
    各种排序
    最大子数组的和与积
    字符串距离
    二叉树的基本操作
    C++11创建线程的几种方式
    二分查找
    汉诺塔问题
    读写锁实现
    全排列
    数字转汉字
  • 原文地址:https://www.cnblogs.com/h-lka/p/11360509.html
Copyright © 2020-2023  润新知