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;
}