差分约束的学习

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,并且需要判断是否有负环,有的话就不存在

3:如果两个点相同,那么互相连0边即可。a-b<=0 && b-a<=0


然后最短路

模版题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

幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候,lxhgww需要满足小朋友们的K个要求。幼儿园的糖果总是有限的,lxhgww想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。

两个注意事项,要求都要分到糖果就是,每一个人至少分到一个糖果。

至少需要多少糖果,就是希望每一个孩子分到的糖果尽量少还要满足要求,实际上就是求最小值,那么我们把式子转化为>=号,并且跑最长路即可


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



这题很坑,需要加边从n往1加。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;

const int inf=0x3f3f3f3f;
const int N=120005;

int n,k;

int head[N],dis[N],tot,tt[N];
struct aa
{
	int to,pre,dis;
}edge[N*4];
void addedge(int x,int y,int z)
{
	edge[++tot].to=y;edge[tot].dis=z;edge[tot].pre=head[x];head[x]=tot;
}

bool b[N];

bool spfa()
{
	dis[0]=0;b[0]=true;
	
	queue<int> q;q.push(0);
	
	while (!q.empty())
	{
		int u=q.front();q.pop();
		
		for (int i=head[u];i;i=edge[i].pre)
		if (dis[edge[i].to]<dis[u]+edge[i].dis)
		{
			int v=edge[i].to;
			dis[v]=dis[u]+edge[i].dis;
			
			tt[v]++;
			if (tt[v]==n) return false;//判环放在外面,只需用判定<strong>是否松弛n次</strong>就好,只要松弛n次,就可以判定有负(正)环!!
			
			if (!b[v]) {b[v]=true;q.push(v);}
		}
		b[u]=false;
	}
	
	return true;
}

int main()
{
	scanf("%d%d",&n,&k);
	int A,B,op;
	while (k--)
	{
		scanf("%d%d%d",&op,&A,&B);
		switch(op)
		{
			case 1:addedge(A,B,0);addedge(B,A,0);break;
			case 2:
			addedge(A,B,1);
			if (A==B) {printf("-1");return 0;}
			break;
			
			case 3:addedge(B,A,0);break;
			case 4:
			addedge(B,A,1);
			if (A==B) {printf("-1");return 0;}
			break;
			case 5:addedge(A,B,0);break;
		}
	}
	
	for (int i=n;i>=1;i--) addedge(0,i,1);
	
	if (!spfa()) {printf("-1");return 0;}
	
	long long ans=0;
	for (int i=1;i<=n;i++) ans+=dis[i];
	
	printf("%lld",ans);
	return 0;
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值