hdu1201,hdu6252差分约束系统
差分约束系统一般用来解决a-b>=c的问题,有n个这样的限制条件,求出某个满足这些条件的解
可以将这个问题转化成最长路问题,即b到a的距离最少为c,而有多条b到a的路的话,我们就取最长的b到a的距离。
将限制条件转化成为一条边,然后求最长路,一般解决最长路问题,我们使用的算法是spfa
入门题 hdu1201
题意:有n个限制条件,区间a到b至少是有c个点,求满足条件的最少端点数
分析:需要满足所有条件,那么首先想到的是差分约束系统。先定义数组G,Gi为0到i有Gi个端点,那么条件a到b区间至少有c个端点可以转化成,Gb-G(a-1)>=c
,显然n个限制条件是不够的,还需要满足1>=G(i+1)-G(i)>=0,转化为,G(i+1)-G(i)>=0和G(i-1)-G(i)>=-1,用这些边构造一个图,然后G(max)即为答案
由于边的数量比较多,用vector构图的话会超时,所以用邻接表加spfa
ac代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; const int maxn = 50000+10; int f[maxn],nex[maxn*3],w[maxn*3],to[maxn*3],cnt; void add(int x,int y,int k) { cnt++; w[cnt]=k; to[cnt]=y; nex[cnt]=f[x]; f[x]=cnt; } bool vis[maxn]; int dis[maxn]; int spaf() { for(int i=0;i<maxn;i++)dis[i]=-1; queue<int>que; que.push(0); vis[0]=1; dis[0]=0; while(que.size()) { // for(int i=0;i<=13;i++)cout<<dis[i]<<" ";cout<<endl; int x=que.front(); que.pop(); vis[x]=0; // cout<<x<<endl; for(int i=f[x];i;i=nex[i]) { // cout<<to[i]<<" "; if(dis[x]+w[i]>dis[to[i]]) { dis[to[i]]=dis[x]+w[i]; if(vis[to[i]]==0) { vis[to[i]]=1; que.push(to[i]); } } } // cout<<endl; } } int main() { int n; cin>>n; for(int i=0;i<maxn;i++)f[i]=0; for(int i=1;i<=n;i++) { int x,y,w; scanf("%d %d %d",&x,&y,&w); add(x,y+1,w); } for(int i=1;i<=50000+1;i++) { add(i-1,i,0); add(i,i-1,-1); } spaf(); printf("%d\n",dis[50000+1]); return 0; }
提升题 hdu6252
题意:给出的也是限制条件,但是也需要注意一个限制条件,dis[i]-dis[i-1]>0
ac代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; const int maxn=2005; int f[maxn],w[maxn*3],to[maxn*3],nex[maxn*3]; bool vis[maxn]; int out[maxn],cnt=0,dis[maxn],n,m,k; void add(int a,int b,int c) { cnt++; w[cnt]=c; to[cnt]=b; nex[cnt]=f[a]; f[a]=cnt; } bool spfa() { for(int i=1; i<maxn; i++)dis[i]=-1,vis[i]=0,out[i]=0; queue<int>que; que.push(1); vis[1]=1; dis[1]=0; while(que.size()) { // for(int i=1;i<=n;i++)printf(" %d",dis[i]);cout<<endl; int x=que.front(); // cout<<x<<"out"<<endl; vis[x]=0; que.pop(); out[x]++; if(out[x]>n) return false; for(int i=f[x]; i; i=nex[i]) { // cout<<to[i]<<"to"<<endl; if(dis[x]+w[i]>dis[to[i]]) { dis[to[i]]=dis[x]+w[i]; if(vis[to[i]]==0) { que.push(to[i]); vis[to[i]]=1; } } } } return true; } int main() { int T; cin>>T; for(int cn=1; cn<=T; cn++) { cnt=0; scanf("%d %d %d",&n,&m,&k); for(int i=1; i<maxn; i++)f[i]=0; for(int i=2; i<=n; i++) add(i-1,i,1); for(int i=1; i<=m; i++) { int a,b,c,d; scanf("%d %d %d %d",&a,&b,&c,&d); if(a==b&&c==d) { add(b,c,k); add(c,b,-k); } else { add(c,b,1-k); add(a,d,k+1); } } if(spfa()) { printf("Case #%d:",cn); for(int i=2;i<=n;i++) printf(" %d",dis[i]-dis[i-1]); cout<<endl; } else printf("Case #%d: IMPOSSIBLE\n",cn); } return 0; }