Hubtown
Hubtown
时间限制: 10 Sec 内存限制: 256 MB
题目描述
A citizen will always take the train line which is of least angular distance from its house. However, if a citizen is exactly in the middle between two train lines, they are willing to take either of them, and city council can decide which of the two train lines the citizen should use.
See Figure H.1 for an example.

Figure H.1: Illustration of Sample Input 1. The dashed arrows indicate which train lines the citizens are closest to (note that we are measuring angular distances, not Euclidean distance).
Your task is to help the council, by finding a maximum size subset of citizens who can go by train in the morning to the central hub, ensuring that each of the citizens take one of the lines they are closest to, while not exceeding the capacity of any train line. For this subset, you should also print what train they are to take.
输入
The next n lines each contain two integers x and y, the Cartesian coordinates of a citizen’s home. No citizen lives at the central hub of the city.
Then follow m lines, each containing three integers x, y, and c describing a train line, where (x, y) are the coordinates of a single point (distinct from the central hub of the city) which the train line passes through and 0 ≤ c ≤ n is the capacity of the train line. The train line is the ray starting at (0, 0) and passing through (x, y).
All coordinates x and y (both citizens’ homes and the points defining the train lines) are bounded by 1000 in absolute value. No two train lines overlap, but multiple citizens may live at the same coordinates.
输出
样例输入
3 2
2 0
-1 0
-2 -1
1 -1 1
1 1 2
样例输出
3
0 1
1 1
2 0
题意:n个人,m个铁轨,每个人要到最近的铁轨去,若最近的有两个可二选一,每个铁轨能承受的人数有限,问最多多少个人可以到铁轨上。
做法:先对人和铁轨一起进行极角排序,然后记录一下距离人最近的上下两个铁轨,之后建图跑最大流。具体细节在代码中说明。
此外,这题能跑最大流是因为网络流跑二分图匹配的时间复杂度是 O(m*sqrt(n)),而且实际编程中速度会更快。
#include<bits/stdc++.h>
#define N 400050
#define M 2000050
using namespace std;
typedef struct
{
int v;
int flow;
} ss; ss edg[M];
vector<int>edges[N];
int now_edges=; void addedge(int u,int v,int flow)
{
// printf(" %d %d %d\n",u,v,flow);
edges[u].push_back(now_edges);
edg[now_edges++]=(ss)
{
v,flow
};
edges[v].push_back(now_edges);
edg[now_edges++]=(ss)
{
u,
};
} int dis[N],S,T;
bool bfs()
{
memset(dis,,sizeof(dis));
queue<int>q;
q.push(S);
dis[S]=; while(!q.empty())
{
int now=q.front();
q.pop();
int Size=edges[now].size(); for(int i=; i<Size; i++)
{
ss e=edg[edges[now][i]];
if(e.flow>&&dis[e.v]==)
{
dis[e.v]=dis[now]+;
q.push(e.v);
}
}
}
if(dis[T]==)
return ;
return ; }
int current[N];
int dfs(int now,int maxflow)
{
if(now==T)
return maxflow;
int Size=edges[now].size();
for(int i=current[now]; i<Size; i++)
{
current[now]=i;
ss &e=edg[edges[now][i]]; if(e.flow>&&dis[e.v]==dis[now]+)
{
int Flow=dfs(e.v,min(maxflow,e.flow)); if(Flow)
{
e.flow-=Flow;
edg[edges[now][i]^].flow+=Flow;
return Flow;
}
}
}
return ;
} int dinic()
{
int ans=,flow;
while(bfs())
{
memset(current,,sizeof(current));
while(flow=dfs(S,INT_MAX/))
ans+=flow;
}
return ans;
} struct orz //铁轨和人的统一结构体,value<0为人,value>0为铁轨
{
int value,number;
int x,y,sgn; void setxy(int a,int b)
{
x=a;
y=b;
if(!x)sgn=y>;
else sgn=x>;
}
}; int cross(int x1,int y1,int x2,int y2)//计算叉积
{
return (x1*y2-x2*y1);
} int compare(orz a,orz b,orz c)//计算极角
{
return cross((b.x-a.x),(b.y-a.y),(c.x-a.x),(c.y-a.y));
} bool cmp(orz a,orz b)
{
if(a.sgn!=b.sgn)return a.sgn<b.sgn;
orz c;//原点
c.x = ;
c.y = ;
if(compare(c,a,b)==)//计算叉积,函数在上面有介绍,如果叉积相等,按照X从小到大排序
return a.number>b.number;
else
return compare(c,a,b)<;
} bool point_on_line(orz a,orz b)
{
int d1=__gcd(abs(a.x),abs(a.y)),d2=__gcd(abs(b.x),abs(b.y));
return (a.x/d1==b.x/d2)&&(a.y/d1==b.y/d2);
} const long double epsss=1e-; struct Point
{
int x,y;
Point() {}
Point(int _x,int _y)
{
x=_x,y=_y;
}
};
struct Pointd
{
long double x,y;
Pointd() {}
Pointd(long double _x,long double _y)
{
x=_x,y=_y;
}
}; int cross(const Point&a,const Point&b)
{
return a.x*b.y-a.y*b.x;
} long double crossd(const Pointd&a,const Pointd&b)
{
return a.x*b.y-a.y*b.x;
} int sig(int x)
{
if(x==)
return ;
return x>?:-;
} int sigd(long double x)
{
if(fabs(x)<epsss)
return ;
return x>?:-;
} int distance_cmp(const orz&_a,const orz&_b,const orz&_c)//判断点a距离哪一条射线近
{
Point a(_a.x,_a.y);
Point b(_b.x,_b.y);
Point c(_c.x,_c.y);
Point d;
if(!cross(b,c))
{
d=Point(-b.y,b.x);
if(!cross(a,d))
return ;
if(sig(cross(d,a))==sig(cross(d,b)))
return -;
return ;
}
long double L=sqrt(b.x*b.x+b.y*b.y);
long double R=sqrt(c.x*c.x+c.y*c.y);
Pointd aa(a.x,a.y);
Pointd bb(b.x,b.y);
Pointd cc(c.x,c.y);
Pointd dd(d.x,d.y);
bb.x*=R;
bb.y*=R;
cc.x*=L;
cc.y*=L;
dd=Pointd(bb.x+cc.x,bb.y+cc.y);
if(!sigd(crossd(aa,dd)))
return ;
if(sigd(crossd(dd,aa))==sigd(crossd(dd,bb)))
return -;
return ;
} orz allpoint[N*];
int up[N],down[N]; int main()
{
int n,m;
scanf("%d %d",&n,&m);
S=n+m+;
T=n+m+; for(int i=; i<=n; i++)
{
int x,y;
scanf("%d %d",&x,&y);
allpoint[i].setxy(x,y);
allpoint[i].value=-;
allpoint[i].number=i;
addedge(S,i,);
} for(int i=; i<=m; i++)
{
int x,y,z;
scanf("%d %d %d",&x,&y,&z);
allpoint[i+n].setxy(x,y);
allpoint[i+n].value=z;
allpoint[i+n].number=i+n;
addedge(i+n,T,z);
} sort(allpoint+,allpoint++n+m,cmp);//对人和铁轨一起进行极角排序 for(int i=n+m;i>=;i--)if(allpoint[i].value>=){down[]=i;break;} //寻找最后一个铁轨
for(int i=;i<=n+m;i++)
{
down[i]=down[i-];
if(allpoint[i].value>=)down[i]=i;
} for(int i=;i<=n+m;i++)if(allpoint[i].value>=){up[n+m+]=i;break;}//寻找第一个铁轨
for(int i=n+m;i>=;i--)
{
up[i]=up[i+];
if(allpoint[i].value>=)up[i]=i;
} for(int i=;i<=n+m;i++)
if(allpoint[i].value<)
{
int a=up[i],b=down[i]; if(a==b)addedge(allpoint[i].number,allpoint[a].number,);
else
if(point_on_line(allpoint[i],allpoint[a]))addedge(allpoint[i].number,allpoint[a].number,);
else
if(point_on_line(allpoint[i],allpoint[b]))addedge(allpoint[i].number,allpoint[b].number,);
else
{
int t=distance_cmp(allpoint[i],allpoint[a],allpoint[b]);
if(t<=)addedge(allpoint[i].number,allpoint[a].number,);
if(t>=)addedge(allpoint[i].number,allpoint[b].number,);
}
} int sum=dinic();
printf("%d\n",sum);
for(int i=; i<=n; i++)
{
int Size=edges[i].size();
for(int j=; j<Size; j++)
{
if(edg[edges[i][j]^].flow&&edg[edges[i][j]].v!=S)//注意这里要判一下另一个点是不是起点
{
printf("%d %d\n",i-,edg[edges[i][j]].v-n-);
break;
}
}
}
return ;
}
Hubtown的更多相关文章
- Hubtown(最大流)
Hubtown 时间限制: 1 Sec 内存限制: 128 MB提交: 23 解决: 11[提交] [状态] [讨论版] [命题人:admin] 题目描述 Hubtown is a large N ...
- 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)
A. Airport Coffee 设$f_i$表示考虑前$i$个咖啡厅,且在$i$处买咖啡的最小时间,通过单调队列优化转移. 时间复杂度$O(n)$. #include<cstdio> ...
- 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017) Solution
A - Airport Coffee 留坑. B - Best Relay Team 枚举首棒 #include <bits/stdc++.h> using namespace std; ...
随机推荐
- 添加 SSH 公钥
生成 SSH 密钥 ssh-keygen -t rsa -C "YOUR_EMAIL@YOUREMAIL.COM" 获取 SSH 公钥信息 cat ~/.ssh/id_rsa.pu ...
- Android计算器简单逻辑实现
Android计算器简单逻辑实现 引言: 我的android计算器的实现方式是:按钮输入一次,就处理一次. 但是如果你学过数据结构(栈),就可以使用表达式解析(前缀,后缀)处理. 而这个方式已经很成熟 ...
- HtmlUnit爬取Ajax动态生成的网页以及自动调用页面javascript函数
HtmlUnit官网的介绍: HtmlUnit是一款基于Java的没有图形界面的浏览器程序.它模仿HTML document并且提供API让开发人员像是在一个正常的浏览器上操作一样,获取网页内容,填充 ...
- WPF中给Button加上图标和文字
要实现在Button里面加入图标或者图形以及文字,我们就需要在Button里面用一个WrapPanel控件,这个WrapPanel控件会把我们的图标或者文字进行包裹,并显示出来. Xaml: < ...
- python基础一 day10(2)
复习: # 三元运算符# 接收结果的变量 = 条件为真的结果 if 条件 else 条件为假的结果# 接收结果的变量 = “真结果” if 条件 else “假结果”## 命名空间 和 作用域# 三种 ...
- 新数据的GT列表
制作新数据集时需要重新制作train_GT,test_GT 代码: dic = {} with open('/home/bnrc/all_image_GT.txt','r') as file: for ...
- 用python编写九九乘法表
for i in range(1,10): for j in range(1,10): if j >i: print(end='') else: print(j,'*',i,'=',i*j,en ...
- Hopfield 网络(上)
讲的什么 这部分主要对 Hopfield 网络作一大概的介绍.写了其模型结构.能量函数和网络的动作方式.主要参考了网上搜到的一些相关 PPT. 概述 早在 1982 年,Hopfield 发表的文 ...
- CAS (Compare and Swap)
synchronized是悲观锁 注意:实现了CAS的有原子类(AtomicInteger,AtomicLong,等等原子类) CAS 是乐观锁,一种高效实现线程安全性的方法 1.支持原子更新操作,适 ...
- ios 注册功能研究学习
通常,移动App的注册功能通常采用手机号码注册或者邮箱帐号注册. 不过在国内这样隐私堪忧的环境下,需要手机号来注册会流失不少用户.即便是新浪微博这样的应用,需要绑定手机号也令我不信任.除非是像淘宝.支 ...