SPOJ Problem Set (classical)2321. SegmentsProblem code: SEGMENTS |
There are N horizontal line segments in the plane. The ith segment has some height hi (which may be negative) and runs from x = ai to x = bi (ai < bi). Segments do not contain their endpoints. You must draw a set of vertical lines (note lines and not line segments) so that every given horizontal segment is intersected at least once and at most R times by vertical lines in such a way that R is minimized.
Input
The first line of the input is N (1 ≤ N ≤ 400), the number of horizontal line segments. N lines then follow, where the ith line is "ai bi hi". Each of ai,bi,hi are 32-bit signed integers. Horizontal segments may overlap.
Output
Your output should consist of a single integer, the smallest value of R that is achievable, followed by a newline.
Example
Input: 3 0 1 5 0 2 -2 1 2 7 Output: 2
题意:在二维坐标给定一条水平直线的起点和终点和高度(直线不包括终点),用一些竖直的直线切这些水平直线,每一条直线至少被切一次,问被切最多的直线最少的切割次数
题解:该题可以用差分约束构图,先离散化,然后每个点之间必定有大于等于0条竖直直线,每条线的2个端点之间必定有大于等于1条竖直直线,然后二分枚举每条直线2个端点之间最多切割的直线的次数,若该次数不使图构成负权环,则可以最大切割次数可以少于等于该值,代码转化为求最短路
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
const int N=805;
const int INF=1<<28;
using namespace std;
struct edge{
long long a,b,h;
}p[N];
struct line{
int x,y,len;
}v[N<<2];
int n,cou,all,dis[N];
map<long long,int>cc;
void input()
{
long long c[N<<1];
cou=0;
for(int i=0;i<n;i++)
{
scanf("%I64d%I64d%I64d",&p[i].a,&p[i].b,&p[i].h);
p[i].a=p[i].a*2,p[i].b=p[i].b*2-1;
c[cou++]=p[i].a,c[cou++]=p[i].b;
}
sort(c,c+cou);
cou=unique(c,c+cou)-c;
for(int i=0;i<cou;i++) cc[c[i]]=i;
}
void add(int x,int y,int len)
{
v[all].x=x;
v[all].y=y;
v[all++].len=len;
}
void build(int len)
{
all=0;
for(int i=0;i<n;i++)
{
int x=cc[p[i].a],y=cc[p[i].b];
add(y,x,-1),add(x,y,len);
}
for(int i=1;i<cou;i++) add(i,i-1,0);
}
int bellman()
{
for(int i=1;i<=cou;i++) dis[i]=INF;
dis[0]=0;
for(int i=0;i<cou;i++)
{
int flag=1;
for(int j=0;j<all;j++)
{
if(dis[v[j].x]+v[j].len<dis[v[j].y])
dis[v[j].y]=dis[v[j].x]+v[j].len,flag=0;
}
if(flag) return 1;
}
return 0;
}
int run()
{
int res=n,l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
build(mid);
if(bellman())
{
r=mid-1;
res=mid;
}
else l=mid+1;
}
return res;
}
int main()
{
//freopen("t.txt","r",stdin);
while(scanf("%d",&n)>0)
{
input();
printf("%d\n",run());
}
return 0;
}