差分约束 小结(gzoi太过分啦,把我的code删啦qwq)

首先讲一下原理(dalao写的,算法导论的不详细):

假设约束系统存在解,我们知道,给定超级源点的一个偏移量d[0](即d[0]不一定为0),就能由最短路径树确定差分约束系统的一组解(树上两点间路径唯一确定)。同样的,给定最短路径树上任一个节点的值d[v],都可以求出超级源点的偏移量d[0],同样也确定了差分约束系统的一组解。对于从0到v的任意一条路径p(0,v1,v2,...,vN,v),其所表示的约束式分别为:x[v1]-x[0] <= 0;x[v2]-x[v1] <= w(v1,v2);...;x[v]-x[vN] <= w(vN,v)。叠加得到x[v]-x[0] <= w(p),令x[0]为确定值d[0],即x[v] <= d[0]+w(p),p为从0到v的任意路径。取p为0到v的最短路p*,就有x[v] <= x[0]+w(p*) <= x[0]+w(p)。则当x[v]=d[0]+w(p*)时x[v]取得最大值。

接下来是模版:

1. x[1]-x[0]<=w<1,0> x[2]-x[1]<=w<2,1> 则在0到1,1到2建一条边为对应的weight,找最长路

2. x[1]-x[0]>=w<1,0> x[2]-x[1]>=w<2,1> 则找最短路

 

接下来是题目

 

Problem A

关系运算图
 

Problem  B

man

 
 

Problem  C

CJB比身高

 
 

Problem  D

树上的猴子

 
 

Problem  E

小K的农场

 A:

Problem A: 关系运算图

Time Limit: 1000 ms   Memory Limit: 128 MB

Description

给出一有向图,图中每条边都被标上了关系运算符‘<’,‘>’,‘=’。现在要给图中每个顶点标上一个大于等于0,小于等于k的某个整数使所有边上的符号得到满足。若存在这样的k,则求最小的k,若任何k都无法满足则输出NO。

 

例如下表中最小的k为2。

 

结点1>结点2

结点2>结点3

结点2>结点4

结点3=结点4

 

如果存在这样的k,输出最小的k值;否则输出‘NO’。

Input

共二行,第一行有二个空格隔开的整数n和m。n表示G的结点个数,m表示G的边数,其中1<=n<=1000, 0<=m<=10000。全部结点用1到n标出,图中任何二点之间最多只有一条边,且不存在自环。

第二行共有3m个用空格隔开的整数,第3i-2和第3i-1(1<=i<=m)个数表示第i条边的顶点。第3i个数表示第i条边上的符号,其值用集合{-1,0,1}中的数表示:-1表示‘<’, 0 表示‘=’, 1表示‘>’。

Output

仅一行,如无解则输出‘NO’;否则输出最小的k的值。

Sample Input

1 2 -1 2 3 0 2 4 -1 3 4 -1

Sample Output

2

 codeeeeeeeeeeeeeeeeeeeee:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#define maxn 1005
using namespace std;
struct edg{
int to,l;
edg(int tt,int ll):to(tt),l(ll){}
};
vector<edg> G[maxn];
int s[maxn],ma;
int in[maxn],st[maxn],tot;
int m,n;
bool pd[maxn];
queue<int> Q;
int main()
{int u,v,wi;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {scanf("%d%d%d",&u,&v,&wi);
    if(wi==1) {G[v].push_back(edg(u,1));in[u]++;}
    if(wi==-1) {G[u].push_back(edg(v,1));in[v]++;}
    if(wi==0) {G[u].push_back(edg(v,0));    
                    G[v].push_back(edg(u,0));}//差分约束建图;
    }
    for(int i=1;i<=n;i++)
    if(in[i]==0) st[++tot]=i;//找最小点,及入度为0;
for(int i=1;i<=tot;i++){
    memset(s,0,sizeof(s));
     memset(in,0,sizeof(in));   
      Q.push(st[i]);
      while(!Q.empty())
      {u=Q.front();Q.pop();pd[u]=false;
          for(unsigned int i=0;i<G[u].size();i++)
          {edg v=G[u][i];
            if(s[v.to]<s[u]+v.l)
            {s[v.to]=s[u]+v.l;
              ma=max(ma,s[v.to]);   
             if(!pd[v.to])
             {Q.push(v.to);pd[v.to]=true;in[v.to]++;}
             if(in[v.to]>n+1) {pd[0]=true;break;}//有负环则退;
             }
         }
         if(pd[0]) break;
     }
if(pd[0]) break; 
}
   if(pd[0]) printf("NO\n");
     else printf("%d\n",ma);
     return 0;
 }

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值