题目大意:给你一些线段的起止点,问你最少用多少条线段可以把一段区间覆盖 线段数<=25000 区间<=1000000
1、spfa+离散化+SLF即可,直接上代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int maxn=1000010,maxm=2000010; using namespace std; int st,ed,tot=0; int f[maxn],now[maxn]; bool b[maxn]; int h[maxm]; int pre[maxm],son[maxm],v[maxm]; inline void cc(int a,int b,int c) { pre[++tot]=now[a]; now[a]=tot; son[tot]=b; v[tot]=c; } inline int read() { char ch; int tmp=0; while(ch=getchar()) if('0'<=ch && ch<='9') break; for(;'0'<=ch && ch<='9';ch=getchar()) tmp=tmp*10+ch-'0'; return tmp; } int a[50010]; inline void init() { int n=read(); st=1; ed=read()+1; for (int i=1;i<=n;i++) { int l=read(); int r=read()+1; cc(l,r,1); a[n+i]=r; a[i]=l; } sort(a+1,a+2*n+1); for (int i=2;i<=2*n;i++) cc(a[i],a[i-1],0); } inline void spfa() { memset(f,63,sizeof(f)); int t=0,w=1; f[st]=0; h[1]=st; b[st]=1; while (t!=w) { if (++t==maxn) t=1; int p=now[h[t]]; while (p) { if (f[h[t]]+v[p]<f[son[p]] && f[h[t]]+v[p]<f[ed]) { f[son[p]]=f[h[t]]+v[p]; if (!b[son[p]]) { b[son[p]]=1; if (++w==maxn) w=1; h[w]=son[p]; int tt=t+1==maxn?1:t+1; if (f[h[tt]]>f[h[w]]) swap(h[tt],h[w]); } } p=pre[p]; } b[h[t]]=0; } if (f[ed]>1000000) f[ed]=-1; printf("%d",f[ed]); } int main() { init(); spfa(); return 0; }
2、dp,先按线段右端点排序,然后线段树优化之,代码没写
3、贪心,先按左段点排序,找到最靠右的右端点即可,贴代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; int getint(){ int sym=1; int res=0; char ch; while(!isdigit(ch=getchar())) if(ch=='-') sym=-1; res=ch-'0'; while(isdigit(ch=getchar())) res=res*10+ch-'0'; return sym*res; } void putint(int x){ if(x<0) putchar('-'),x=-x; if(x>=10) putint(x/10); putchar(x%10+'0'); } const int maxn=25010; typedef pair<int,int> PII; PII seg[maxn]; int n,m; bool cmp_l(const PII &a,const PII &b){ return a.first<b.first || a.first==b.first && a.second>b.second; } void init(){ n=getint(),m=getint(); for(int i=1;i<=n;++i) seg[i].first=getint()-1,seg[i].second=getint(); sort(seg+1,seg+n+1,cmp_l); seg[n+1]=make_pair(m,m); } int min_seg(){ if(seg[1].first>1) return -1; int maxr=0,ans=0; for(int i=1,nowr=0;i<=n+1 && maxr<m;++i){ if(seg[i].first<=maxr){ nowr=max(nowr,seg[i].second); continue; } maxr=nowr; if(seg[i].first>maxr) return -1; ++ans,nowr=seg[i].second; } if(maxr<m) return -1; return ans; } int main(){ init(); printf("%d\n",min_seg()); return 0; }