poj 1201 http://poj.org/problem?id=1201
题目大意: 给定n的闭区间 [ai,bi],找到一个长度最小的序列s,使这个序列在每个区间内至少有ci个数。
思路:spfa+差分约束。第一次写差分约束。用d[i]表示序列s在区间[0,i]内包含元素的个数,则由题意,d[v] - d[u-1] > w[i] ,即d[v] > d[u-1]+w[i],这就是spfa求最长路满足的条件: if(d[u[j]] < d[x]+w[j]) d[u[j]]=d[x]+w[j];所以,就可以以ai,bi为节点,ci为边权建图。此外,题目中还存在隐藏条件,0 <= d[i+1] - d[i] <= 1。
代码:
/*
ID: czq1992
LANG: C++
TASK: poj1201
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define MAXN 50010
#define inf 100000
int u[MAXN*3],v[MAXN*3],w[MAXN*3];
int first[MAXN*3],next[MAXN*3],d[MAXN];
int cnt=0,n;
int spfa(int s, int e)
{
//cout<<s<<" "<<e<<endl;
queue<int> q;
bool inq[MAXN];
for(int i=0;i<MAXN;i++) d[i]=-inf;
memset(inq,0,sizeof(inq));
q.push(s);
d[s]=0;inq[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
inq[x]=false;
//cout<<"???"<<x<<endl;
for(int j=first[x];j!=-1;j=next[j])
if(d[u[j]] < d[x]+w[j])
{
d[u[j]]=d[x]+w[j];
//cout<<v[j]<<"----"<<d[v[j]]<<endl;
if(!inq[u[j]])
{
inq[u[j]]=true;
q.push(u[j]);
}
}
}
//for(int i=s;i<=e;i++) cout<<d[i]<<endl;
return d[e];
}
void add(int va,int ua,int ww)
{
next[cnt]=first[va];
first[va]=cnt;
u[cnt]=ua;
v[cnt]=va;
w[cnt]=ww;
cnt++;
}
int main()
{
int i,j;
int mmax,mmin;
int a,b,c;
while(scanf("%d", &n)!=EOF)
{
cnt=0;
memset(first,-1,sizeof(first));
memset(next,0,sizeof(next));
memset(u,0,sizeof(u));
memset(v,0,sizeof(v));
memset(w,0,sizeof(w));
//for(i=0;i<MAXN;i++) first[i]=-1;
mmax=-inf;
mmin=inf;
for(i=0;i<n;i++)
{
scanf("%d%d%d",&a,&b, &c);
b++;
add(a,b,c);
mmax=max(mmax,b);
mmin=min(mmin,a);
}
//cout<<mmin<<" "<<mmax<<endl;
for(i=mmin;i<mmax;i++)
{
add(i,i+1,0);
add(i+1,i,-1);
}
printf("%d\n",spfa(mmin,mmax));
}
return 0;
}