洛谷P3357 最长k可重线段集问题(费用流)
2018-06-17 21:03:00来源:未知 阅读 ()
题目描述
给定平面 x-O-yx−O−y 上 nn 个开线段组成的集合 II ,和一个正整数 kk 。试设计一个算法,从开线段集合 II 中选取出开线段集合 S\subseteq IS⊆I ,使得在 xx 轴上的任何一点 pp ,SS 中与直线 x=px=p 相交的开线段个数不超过 kk ,且\sum\limits_{z\in S}|z|z∈S∑?∣z∣ 达到最大。这样的集合 SS 称为开线段集合 II 的最长 kk 可重线段集。\sum\limits_{z\in S}|z|z∈S∑?∣z∣ 称为最长 kk 可重线段集的长度。
对于任何开线段 zz ,设其断点坐标为 (x_0,y_0)(x0?,y0?) 和 (x_1,y_1)(x1?,y1?) ,则开线段 zz 的长度 |z|∣z∣ 定义为:|z|=\lfloor\sqrt{(x_1-x_0)^2+(y_1-y_0)^2}\rfloor∣z∣=⌊(⌋
对于给定的开线段集合 II 和正整数 kk ,计算开线段集合 II 的最长 kk 可重线段集的长度。
输入输出格式
输入格式:
文件的第一 行有 22 个正整数 nn 和 kk ,分别表示开线段的个数和开线段的可重叠数。
接下来的 nn 行,每行有 44 个整数,表示开线段的 22 个端点坐标。
输出格式:
程序运行结束时,输出计算出的最长 kk 可重线段集的长度。
输入输出样例
4 2 1 2 7 3 6 5 8 3 7 8 10 5 9 6 13 9
17
说明
1\leq n\leq5001≤n≤500
1 \leq k \leq 131≤k≤13
这题与最长k可重区间集问题本质上是一样的,
但是有一种特殊情况,当这条直线垂直于$y$轴时,我们在连边的过程中会产生负环
怎么办呢?
这里有一个神仙操作
把两个点的$x$值全部*2,若相同,则较小的-1,否则较小的+1
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<vector> #include<cmath> #define int long long #define AddEdge(x,y,z,f) add_edge(x,y,z,f),add_edge(y,x,-z,0) using namespace std; const int MAXN=1e5+10; const int INF=1e8+10; inline int read() { char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int N,K,S,T; int anscost=0; struct node { int u,v,w,f,nxt; }edge[MAXN]; int head[MAXN],num=2; inline void add_edge(int x,int y,int z,int f) { edge[num].u=x; edge[num].v=y; edge[num].w=z; edge[num].f=f; edge[num].nxt=head[x]; head[x]=num++; } int Pre[MAXN],vis[MAXN],dis[MAXN]; bool SPFA() { queue<int>q; memset(dis,0x3f,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[S]=0; q.push(S); while(q.size()!=0) { int p=q.front();q.pop(); vis[p]=0; for(int i=head[p];i!=-1;i=edge[i].nxt) { if(dis[edge[i].v]>dis[p]+edge[i].w&&edge[i].f) { dis[edge[i].v]=dis[p]+edge[i].w; Pre[edge[i].v]=i; if(!vis[edge[i].v]) vis[edge[i].v]=1,q.push(edge[i].v); } } } return dis[T]<=INF; } void f() { int nowflow=INF; for(int now=T;now!=S;now=edge[Pre[now]].u) nowflow=min(nowflow,edge[Pre[now]].f); for(int now=T;now!=S;now=edge[Pre[now]].u) edge[Pre[now]].f-=nowflow, edge[Pre[now]^1].f+=nowflow; anscost+=nowflow*dis[T]; } void MCMF() { int ans=0; while(SPFA()) f(); printf("%lld\n",-anscost); } int L[MAXN],R[MAXN],date[MAXN],tot=0; struct Point { int xx1,yy1,xx2,yy2,L; }P[MAXN]; double GetL(int n) { return floor((double)sqrt((P[n].xx1-P[n].xx2)*(P[n].xx1-P[n].xx2) + (P[n].yy1-P[n].yy2)*(P[n].yy1-P[n].yy2))); } main() { #ifdef WIN32 freopen("a.in","r",stdin); #else #endif memset(head,-1,sizeof(head)); N=read();K=read(); for(int i=1;i<=N;i++) { P[i].xx1=read(),P[i].yy1=read(),P[i].xx2=read(),P[i].yy2=read(); if(P[i].xx1>P[i].xx2) swap(P[i].xx1,P[i].xx2), swap(P[i].yy1,P[i].yy2); P[i].L=GetL(i); P[i].xx1*=2; P[i].xx2*=2; if(P[i].xx1==P[i].xx2) P[i].xx1--; else P[i].xx1++; date[++tot]=P[i].xx1,date[++tot]=P[i].xx2; } sort(date+1,date+tot+1); int num=unique(date+1,date+tot+1)-date-1; for(int i=1;i<=num-1;i++) AddEdge(i,i+1,0,INF); for(int i=1;i<=N;i++) { P[i].xx1=lower_bound(date+1,date+num+1,P[i].xx1)-date; P[i].xx2=lower_bound(date+1,date+num+1,P[i].xx2)-date; AddEdge(P[i].xx1,P[i].xx2,-P[i].L,1); } S=0,T=num*2; AddEdge(S,1,0,K); AddEdge(num,T,0,K); MCMF(); return 0; }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 洛谷P1164->小A点菜 2020-05-18
- 最长回文子串 2020-04-13
- 无重复字符的最长子串 2020-04-08
- 洛谷P1907口算练习题 2020-03-24
- 结题报告--P5551洛谷--Chino的树学 2020-03-13
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash