题目传送门:https://www.luogu.org/problemnew/show/P3084
题意:
有n头奶牛,m张照片,每张照片都覆盖了连续一段奶牛,且每张照片中都有至少一头斑点奶牛,但是这些照片不一定把每一头奶牛都拍了进去。求至少有多少只斑点奶牛,若无解,输出-1。
思路:
由题意可知:
1.每一个区间最多一头奶牛
2.每一个区间最少一头奶牛
我们可以得到:
1. 0≤a[i]-a[i-1]≤1(每一头相邻的奶牛有且仅有一头斑点奶牛)
2. 0≤a[y]-a[x-1]≤1(每一个区间——被找到的区间,有且仅有一头斑点奶牛)
可变形为:
1. a[i]-a[i-1]≤1
2. a[y]-a[x-1]≤1
然后我们可以发现:这两条式子满足差分约束系统。
我们就可以建边了:
1.i-1向i建一条长度为1的边,i向i-1建一条长度为0的边
2.x-1向y建一条长度为1的边,y向x-1建一条长度为-1的边
最后就跑最短路即可。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define I inline
#define R register
#define INF 1000000
using namespace std;
deque<int> f;
int n,m,k,len=0,tot=0;
int p[400010],last[400010];
struct node{int x,y,z,next;} a[800010];
int dis[400010],q[400010];
bool bz[400010];
I int readint()
{
int f=1,x=0;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())
if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';x=(x<<3)+(x<<1)+(ch^48),ch=getchar());
return x*f;
}
I void ins(int x,int y,int z)
{
a[++len].x=x;a[len].y=y;a[len].z=z;a[len].next=last[x];last[x]=len;
}
I int spfa()
{
for(int i=1;i<=n;i++)
dis[i]=1e7;
dis[0]=0;
f.push_back(0);
while(!f.empty())
{
int x=f.front();
f.pop_front();
bz[x]=false;
for(R int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(dis[x]+a[i].z<dis[y])
{
dis[y]=dis[x]+a[i].z;
if(!bz[y])
{
if(++tot>=INF) return -1;//判负环,不是正确的,只是题目卡差分约束,普通的过不了,只好“特判”
bz[y]=true;
if(!f.empty()&&dis[y]<dis[f.front()]) f.push_front(y); else f.push_back(y);
}
}
}
}
return dis[n];
}
int main()
{
int x,y;
n=readint(),m=readint();
for(R int i=1;i<=m;i++)
{
x=readint(),y=readint();
ins(x-1,y,1),ins(y,x-1,-1);
}
for(R int i=1;i<=n;i++)
ins(i-1,i,1),ins(i,i-1,0);
printf("%d",spfa());
}