题意

有n个城市,m个边界线,p名士兵。现在士兵要按一定顺序攻占城市,但从一个城市到另一个城市的过程中不能穿过边界线。士兵有一个容量为K的背包装粮食,士兵到达一个城市可以选择攻占城市或者只是路过,如果攻占城市,就能装满背包。从城市到城市消耗的粮食等于两城市的距离,如果距离大于士兵当前的背包的容量,士兵就不能走这条路。士兵可以选择空降一次,空降不耗费。求p个士兵攻占所有城市所需要的最小背包容量k。

来源:2013 暑期多校联合训练 第一场

思路

非常好的一道比较综合的题目~首先我们能想到这是可相交的最小路径覆盖,当然还需处理一些问题:

距离。两个城市之间如果有边界线,我们还得绕着走,把边界线的两端点计算在内。为了方便,我们可以把所有城市和边界线的端点都当作图中的点,然后Floyd求最短路。当然,如果两个城市之间有边界线阻隔(判断线段相交),则这两个城市间不能直接连边。进一步(很重要),在计算包括所有边界线端点的图时,要判断的是如果任意两点的线段与某个边界线相交,则这两点都不能直接连边

点约束访问顺序。如果order[i] < order[j],则添加有向边(i, j)即可。

然后就是二分背包容量,根据最小路径覆盖是否小于士兵人数来更新答案。

代码

[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, m) for (int i = begin; i < begin+m; i ++)
using namespace std;

const double oo = 1e50;
const double eps = 1e-8;
bool dy(double x,double y) { return x > y + eps;} // x > y
bool xy(double x,double y) { return x < y - eps;} // x < y
bool dyd(double x,double y) { return x > y - eps;} // x >= y
bool xyd(double x,double y) { return x < y + eps;} // x <= y
bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y

struct Point{
double x, y;
Point() {}
Point(double _x, double _y){
x = _x, y = _y;
}
Point(const Point &p){
x = p.x, y = p.y;
}
Point operator -(const Point &b)const{
return Point(x - b.x, y - b.y);
}
double operator *(const Point &b)const{
return x * b.y - y * b.x;
}
double operator &(const Point &b)const{
return x * b.x + y * b.y;
}
};
/** 两点间距离平方 **/
double dist2(Point a, Point b){
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}

struct Line{
Point s, e;
double k; //Slope
Line() {}
Line(Point _s, Point _e){
s = _s, e = _e;
k = atan2(e.y - s.y, e.x - s.x);
}
Line(double _sx, double _sy, double _ex, double _ey){
s = Point(_sx, _sy), e = Point(_ex, _ey);
k = atan2(_ey - _sy, _ex - _sx);
}
};
/** 线段相交,相交返回true **/
bool intersection(Line l1,Line l2){
return (max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) &&
max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) &&
max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) &&
max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) &&
((l2.s-l1.s)*(l1.e-l1.s))*((l2.e-l1.s)*(l1.e-l1.s)) < 0 &&
((l1.s-l2.s)*(l2.e-l2.s))*((l1.e-l2.s)*(l2.e-l2.s)) < 0);
}

const int MAXV = 205; //|V1|+|V2|
struct MaximumMatchingOfBipartiteGraph{
int vn;
vector <int> adj[MAXV];
void init(int n){ //二分图两点集点的个数
vn = n;
for (int i = 0; i <= vn; i ++) adj[i].clear();
}
void add_uedge(int u, int v){
adj[u].push_back(v);
adj[v].push_back(u);
}
bool vis[MAXV];
int mat[MAXV]; //记录已匹配点的对应点
bool cross_path(int u){
for (int i = 0; i < (int)adj[u].size(); i ++){
int v = adj[u][i];
if (!vis[v]){
vis[v] = true;
if (mat[v] == 0 || cross_path(mat[v])){
mat[v] = u;
mat[u] = v;
return true;
}
}
}
return false;
}
int hungary(){
MEM(mat, 0);
int match_num = 0;
for (int i = 1; i <= vn; i ++){
MEM(vis, 0);
if (!mat[i] && cross_path(i)){
match_num ++;
}
}
return match_num;
}
void print_edge(){
for (int i = 1; i <= vn; i ++){
for (int j = 0; j < (int)adj[i].size(); j ++){
printf("u = %d v = %d\n", i, adj[i][j]);
}
}
}
}match;

Line barrier[102];
Point city[102];
int order[102];
Point po[302];
double map[302][302];

void build(int n, int m){
REP(i, 1, n+2*m)
REP(j, 1, n+2*m)
map[i][j] = oo;
REP(i, 1, n+2*m)
REP(j, 1, n+2*m){
bool ok = true;
REP(k, 1, m){
Line tmp1 = Line(po[i], po[j]);
if (intersection(tmp1, barrier[k])){
ok = false;
break;
}
}
if (ok){
map[i][j] = sqrt(dist2(po[i], po[j]));
}
}
//floyd
REP(k, 1, n+2*m) REP(i, 1, n+2*m) REP(j, 1, n+2*m){
map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
}
}

int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
int t;
scanf("%d", &t);
while(t --){
int n, m, p;
scanf("%d %d %d", &n, &m, &p);
REP(i, 1, n){
int x, y;
scanf("%d %d", &x, &y);
city[i] = Point(x, y);
po[i] = city[i];
}
REP(i, 1, m){
int x1, y1, x2, y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
barrier[i] = Line(x1, y1, x2, y2);
po[i+n] = barrier[i].s;
po[i+n+m] = barrier[i].e;
}
REP(i, 1, n){
int tmp;
scanf("%d", &tmp);
order[tmp] = i;
}
build(n, m);
// REP(i, 1, n+2*m)
// REP(j, 1, n+2*m){
// printf("i = %d j = %d dis = %f\n", i, j, map[i][j]);
// }
double l = 0.0, r = 1000010.0;
while(xy(l, r)){
double mid = MID(l, r);
match.init(2*n);
REP(i, 1, n)
REP(j, 1, n){
if (order[i] < order[j] && xyd(map[i][j], mid))
match.add_uedge(i, j+n);
}
if (n - match.hungary() > p){
l = mid;
}
else{
r = mid;
}
}
printf("%.2f\n", l);
}
return 0;
}
[/cpp]

HDU 4606 Occupy Cities ★(线段相交+二分+Floyd+最小路径覆盖)的更多相关文章

  1. HDU 4606 Occupy Cities (计算几何+最短路+二分+最小路径覆盖)

    Occupy Cities Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  2. hdu 4606 简单计算几何+floyd+最小路径覆盖

    思路:将所有的直线的两个端点和城市混在一起,将能直接到达的两个点连线,求一次floyd最短路径.二分枚举bag容量,然后按给的要先后占领的城市由前向后,把能到一步到达的建一条边.然后求一次最小路径覆盖 ...

  3. POJ-2594 Treasure Exploration,floyd+最小路径覆盖!

                                                 Treasure Exploration 复见此题,时隔久远,已忘,悲矣! 题意:用最少的机器人沿单向边走完( ...

  4. POJ 2594 Treasure Exploration (Floyd+最小路径覆盖)

    <题目链接> 题目大意: 机器人探索宝藏,有N个点,M条边.问你要几个机器人才能遍历所有的点. 解题分析: 刚开始还以为是最小路径覆盖的模板题,但是后面才知道,本题允许一个点经过多次,这与 ...

  5. Treasure Exploration---poj2594(传递闭包Floyd+最小路径覆盖)

    题目链接:http://poj.org/problem?id=2594 在外星上有n个点需要机器人去探险,有m条单向路径.问至少需要几个机器人才能遍历完所有的点,一个点可以被多个机器人经过(这就是和单 ...

  6. POJ2594:Treasure Exploration(Floyd + 最小路径覆盖)

    Treasure Exploration Time Limit: 6000MS   Memory Limit: 65536K Total Submissions: 9794   Accepted: 3 ...

  7. HDU 4606 Occupy Cities (计算几何+最短路+最小路径覆盖)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题目:给出n个城市需要去占领,有m条线段是障碍物, ...

  8. hdu 4606 Occupy Cities

    http://acm.hdu.edu.cn/showproblem.php?pid=4606 两点之间如果有线段相隔的话,他们的最短路就需要经过线段的端点 把所有线段的端点也加入点数组中,求任意两个点 ...

  9. poj 3216 Repairing Company(最短路Floyd + 最小路径覆盖 + 构图)

    http://poj.org/problem?id=3216 Repairing Company Time Limit: 1000MS   Memory Limit: 131072K Total Su ...

随机推荐

  1. myeclipse 10的破解以及运行run.bat错误或者双击立即消失的问题

    安装包下载: ed2k://|file|[myeclipse.10.0.更新发布].myeclipse-10.0-offline-installer-windows.exe|947752488|73b ...

  2. hdu 1800 Flying to the Mars(简单模拟,string,字符串)

    题目 又来了string的基本用法 //less than 30 digits //等级长度甚至是超过了int64,所以要用字符串来模拟,然后注意去掉前导零 //最多重复的个数就是答案 //关于str ...

  3. LA 3350

    The NASA Space Center, Houston, is less than 200 miles from San Antonio, Texas (the site of the ACM ...

  4. Xcode显示行号

  5. ScriptManager.RegisterStartupScript方法和Page.ClientScript.RegisterStartupScript() 区别

    ScriptManager.RegisterStartupScript方法 如果页面中不用Ajax,cs中运行某段js代码方式可以是: Page.ClientScript.RegisterStartu ...

  6. Struts2.0 去掉action后缀名

    刚刚接触Struts2.0,发现默认请求都会带着后缀名:action 就如下图,url地址中会暴露login.action(请原谅struts拼写错误..) 作为一个URL简洁爱(chu)好(nv)者 ...

  7. Android 核心分析 之六 IPC框架分析 Binder,Service,Service manager

    IPC框架分析 Binder,Service,Service manager 我首先从宏观的角度观察Binder,Service,Service Manager,并阐述各自的概念.从Linux的概念空 ...

  8. Linux资源监控命令/工具(调试)

    1.直接将指令丢到背景中执行:& [root@linux ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 & ...

  9. 265. Paint House II

    题目: There are a row of n houses, each house can be painted with one of the k colors. The cost of pai ...

  10. java string,需要进行首字母大写改写

    java string,需要进行首字母大写改写,网上大家的思路基本一致,就是将首字母截取,转化成大写然后再串上后面的,类似如下代码 //首字母大写     public static String c ...