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