http://www.cnblogs.com/wangfang20/p/3196858.html
题意:
求集合Z中至少要包含多少个元素才能是每个区间[ai,bi]中的元素与Z中的元素重合个数为ci。
思路:对于dis[b]-dis[a]>=c的形式,我们建一条a到b的边,权值为c,最后求最长路就是要得到的最小值。
可举一例,[1,8]假使有7个不同的数,[1,4]假使有2个不同的数,[4,8]假使有3个不同的数,都满足f[8]-f[1]>=7,f[4]-f[1]>=2,f[8]-f[4]>=3.若求最短路,那么肯定得到的结果是5,与f[8]-f[1]>=7相矛盾。故求得是最长路,得到7就是最小的结果。
可是紧紧这样建边,并不能将每个离散的点整合到一个图中,对于任何一个单元区间,1=>f[i+1]-f[i]>=0,故我们就可以得到两个式子f[i+1]-f[i]>=0与f[i]-f[i+1]>=-1;
最后根据式子建边,求差分约束。
要注意的是要将右边界+1,。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define inf 1<<30 #define Maxn 51000 #define Maxm 500000 using namespace std; int dis[Maxn],vi[Maxn],minn,maxn,index[Maxn],e,Que[1000010]; struct Edge{ int to,next,val; }edge[Maxm]; void init() { for(int i=0;i<=Maxn-1;i++) dis[i]=-inf; memset(vi,0,sizeof(vi)); memset(index,-1,sizeof(index)); e=maxn=0; minn=inf; } void addedge(int from,int to,int val) { edge[e].to=to; edge[e].val=val; edge[e].next=index[from]; index[from]=e++; } int spfa() { int i,j,temp,head,rear; head=rear=0; Que[head++]=minn; dis[minn]=0; //cout<<maxn<<endl; while(head!=rear) { temp=Que[rear++]; //cout<<temp<<endl; vi[temp]=0; for(i=index[temp];i!=-1;i=edge[i].next) { int now=edge[i].to; if(dis[now]<dis[temp]+edge[i].val) { dis[now]=dis[temp]+edge[i].val; if(!vi[now]) Que[head++]=now; vi[now]=1; } } } return dis[maxn]; } int main() { int i,j,n,a,b,c; while(scanf("%d",&n)!=EOF) { init(); //cout<<"ok"<<endl; for(i=1;i<=n;i++) { scanf("%d%d%d",&a,&b,&c); b++; minn=min(minn,a); maxn=max(maxn,b); addedge(a,b,c); } for(i=minn;i<maxn;i++) { addedge(i,i+1,0); addedge(i+1,i,-1); } printf("%d ",spfa()); } return 0; }