差分约束的学习

http://www.cnblogs.com/void/archive/2011/08/26/2153928.html很好的概述

实际上就是,这个系统通过,建图找最短路来解;

几种情况

1: x-y<=b约束时,直接addedge(a,b,c);

2: x-y>=b约束时,added(b,a,-1);

实际上,其他的不用管,只要把样式化为x-y=c的样式就可以,别的根本不用管,建完图套最短路即可

自我感觉,先判断两个数 a 和b的大小关系,列出关系式,再转化为标准的样式,然后建图,对了,如果找最大,那么 最短路 +"<=" 号

如果找最小, 最长路 + ">="号

1. 如果要求最大值想办法把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x权值为k的边,变得时候注意 x-y<k =>   x-y<=k-1

   如果要求最小值的话,变为x-y>=k的标准形式,然后建立一条从y到x的k边,求出最长路径即可(即如果最小值,改为>=)然后套模版

2.如果权值为正,用dj,spfa,bellman都可以,如果为负不能用dj,并且需要判断是否有负环,有的话就不存在


然后最短路

模版题poj3159

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<iostream>
#include<stack>

using namespace std;
const int inf=0x3f3f3f3f;
struct
{
	int pre,v,c;
} edge[150009]; 

int n,m,k,head[100009],dist[100009];

void addedge(int u,int v,int c)
{
	k++;edge[k].c=c;edge[k].v=v;edge[k].pre=head[u];head[u]=k;
}

bool b[100009]={false};
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		addedge(a,b,c);
	}//直接建图
	memset(dist,inf,sizeof(dist));//最短路的题,初始值都要设成inf,别忘了
	dist[1]=0;
	stack<int> s;
	s.push(1);
	b[1]=true;
	while (!s.empty())
	{
		int r=s.top();
		s.pop();
		for (int i=head[r];i;i=edge[i].pre)
		{
			int vv=edge[i].v,cc=edge[i].c;
			
			if (dist[vv]>dist[r]+cc)
			{
			
				dist[vv]=dist[r]+cc;
				if (!b[vv]) s.push(vv),b[vv]=true;
			}
		}
		b[r]=false;
	}//用的spfa,事实证明,spfa可以用栈实现
	
	printf("%d",dist[n]);
	return 0;
	
}

scoi2011 bzoj 2330(稍微复杂一点,有几种情况需要判断,并且他问总共的最少糖果数,把单人的最少数量都加起来成和即可,还有别忘建一个超级源,dist【i】是和原点的距离,即最少需要的糖果数,因为,每一个人都要有糖,初始到超级源的距离就为1,因为1就已经是最少了)

/**************************************************************
    Problem: 2330
    User: zhhx
    Language: C++
    Result: Accepted
    Time:272 ms
    Memory:7624 kb
****************************************************************/
 
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<cctype>
#include<queue>
using namespace std;
 
const int maxn=100009;
 
struct
{
    int v,w,to;
}edge[400009];//刚开始数组开小了,bzoj上wrong了好几次
int tot=0,n,k,head[maxn]={0},dist[maxn]={0},y[maxn];
bool b[maxn],o=true;;
void addedge(int u,int v,int w)
{
    tot++;edge[tot].v=v;edge[tot].w=w;edge[tot].to=head[u];head[u]=tot;
}
void spfa()
{
    queue<int> q;
    q.push(0);
    b[0]=true;
    y[0]=1;
    while (!q.empty())
    {
        int r=q.front();
        q.pop();
        for (int i=head[r];i;i=edge[i].to)
        {
            int v=edge[i].v,w=edge[i].w;
            if (dist[v]<dist[r]+w)//这里是找最远路 
            {
                dist[v]=dist[r]+w;
                y[v]++;
                if (y[v]==n) 
                {
                    o=false;
                    return ;
                }//判断环,放在外面,不是放在if(!b【v】)的里面,勿忘 
                if (!b[v])//如果有不符的环,就说明,条件有冲突,不能完成
                {
                    b[v]=true;
                    q.push(v);
                }
            }           
        }
        b[r]=false;
    }
     
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=k;i++)
    {
        int x,a,b;
        scanf("%d%d%d",&x,&a,&b);
        if (x==1) addedge(a,b,0),addedge(b,a,0);
        if (x==2)
          
            if (a==b) {printf("-1");return 0;}
                    else addedge(a,b,1);
         
        if (x==3) addedge(b,a,0);
        if (x==4)
         
            if (a==b) {printf("-1");return 0;}
                    else addedge(b,a,1);
         
        if (x==5) addedge(a,b,0);
    }
    for (int i=n;i>=1;i--) addedge(0,i,1);//每一个人都要有糖果,所以说至少为一,这是建一个超级原点
    spfa();
    long long ans=0;
     
    for (int i=1;i<=n;i++)   ans+=dist[i];//把每一个人最少的糖果数加起来
 
    if (!o) printf("-1");
    else  printf("%lld",ans);
     
    return 0;
}





你可能感兴趣的:(差分约束的学习)