HDU 4606 Occupy Cities 解题报告
来源:互联网 发布:mysql decode 函数 编辑:程序博客网 时间:2024/05/18 22:44
题目
2013 多校训练 第一场
题意:
有n个城市,m个边界线,p名士兵。现在士兵要按一定顺序攻占城市,但从一个城市到另一个城市的过程中不能穿过边界线。士兵有一个容量为K的背包装粮食,士兵到达一个城市可以选择攻占城市或者只是路过,如果攻占城市,就能装满背包。从城市到城市消耗的粮食等于两城市的距离,如果距离大于士兵当前的背包的容量,士兵就不能走这条路。士兵可以选择空降一次,空降不耗费。求p个士兵攻占完所有城市所需要的最小背包容量k。
解法:
很容易想到二分答案。
先用线段求交和floyed求出两个城市之间的最短距离(即两城市路上不攻占任何城市的最小花费),两个城市(u,v)如果从u到v需要跨过边境线或者城市u在v之后被攻占其距离就设为inf。
现在问题变成p个士兵攻打n个城市,如果某两个城市间距离小于mid就可达,如何判断能否攻占完n个城市?
利用二分图匹配,最小路径覆盖:在一个P*P的有向图中,在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联,最小路径=点数-最大匹配数。只需要判断最小路径覆盖是否小于等于p即可,因为最小路径覆盖即攻占完所有城市所需要的最少士兵数。
代码:
#include #include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;#define maxn 105const double EPS=1e-6;const int INF=1000000000;int n,m,p;int ord[maxn],result[maxn];bool state[maxn];double dis[maxn*3][maxn*3];int dcmp(double x){ if (fabs(x)<EPS) return 0; return x<0?-1:1;}struct Point{ double x,y; Point(){} Point(double a,double b):x(a),y(b){} Point operator+(const Point &a)const{ return Point(x+a.x,y+a.y); } Point operator-(const Point &a)const{ return Point(x-a.x,y-a.y); } void input() { scanf("%lf%lf",&x,&y); }}C[maxn*3];struct Line{ Point a,b;}L[maxn];typedef Point Vector;double Cross(Vector a,Vector b){ return a.x*b.y-a.y*b.x;}double Dot(Vector a,Vector b){ return a.x*b.x+a.y*b.y;}double Dist(Vector a){ return sqrt(Dot(a,a));}bool Ispinter(Point a,Point b,Point c,Point d){ double c1=Cross(b-a,c-a),c2=Cross(b-a,d-a), c3=Cross(d-c,a-c),c4=Cross(d-c,b-c); return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;}int find(int x,double key){ for (int i=1;i<=n;i++) if (!state[i]&&dis[x][i]<key+EPS) { state[i]=1; if (!result[i]||find(result[i],key)) { result[i]=x; return 1; } } return 0;}int solve(double key){ int ans=0; memset(result,0,sizeof(result)); for (int i=1;i<=n;i++) { memset(state,0,sizeof(state)); if (find(i,key)) ans++; } return n-ans;}int main(){ //freopen("/home/christinass/code/in.txt","r",stdin); int cas,d,num; scanf("%d",&cas); while (cas--) { scanf("%d%d%d",&n,&m,&p); for (int i=1;i<=n;i++) C[i].input(); num=n; for (int i=1;i<=m;i++) { L[i].a.input(),L[i].b.input(); C[++num].x=L[i].a.x,C[num].y=L[i].a.y; C[++num].x=L[i].b.x,C[num].y=L[i].b.y; } for (int i=1;i<=n;i++) { scanf("%d",&d); ord[d]=i; } for (int i=1;i<=num;i++) for (int j=1;j<=num;j++) dis[i][j]=INF; for (int i=1;i<=num;i++) for (int j=i+1;j<=num;j++) { bool flag=1; for (int k=1;k<=m&&flag;k++) if (Ispinter(C[i],C[j],L[k].a,L[k].b)) flag=0; if (flag) dis[i][j]=dis[j][i]=Dist(C[i]-C[j]); } for (int k=1;k<=num;k++) for (int i=1;i<=num;i++) for (int j=1;j<=num;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (ord[i]>=ord[j]) dis[i][j]=INF; double l=0,r=INF; while (l<r-EPS) { double mid=(l+r)/2; if (solve(mid)<=p) r=mid; else l=mid; } printf("%.2f\n",(l+r)/2); } return 0;}
小结:
二分图有关的其他性质:
最小点覆盖=最大匹配。给定一个二分图G=(V,E),定义一个点如果被覆盖,那么称所有与这个点相邻的弧被覆盖,求最少需要覆盖多少个点才能覆盖所有的边。
最大独立集=顶点数-最大匹配。独立集:图中两两互不连通的顶点构成的集合。
最小路径覆盖=顶点数-最大匹配。
- HDU 4606 Occupy Cities 解题报告
- 2013 Multi-University Training Contest 1 Occupy Cities HDU 4606
- hdu 4606 Occupy Cities(几何+二分+KM)
- HDU 4606 Occupy Cities (计算几何+最短路+最小路径覆盖)
- hdu 4606 Occupy Cities - 计算几何 + 最短路 + 最小路径覆盖
- hdu 4606 Occupy Cities (计算几何+最短路+有向图最小路径覆盖)
- hdu 4606 Occupy Cities(线段相交+最小路径覆盖+二分)
- HDU 4606 Occupy Cities (计算几何+Floyd+二分+最小路径覆盖)
- HDU3371 Connect the Cities 解题报告--prim
- 杭电多校联合第一场hdu4606 occupy cities
- 1001. Battle Over Cities - Hard Version (35)解题报告
- HDU 3342 解题报告
- HDU 3336 解题报告
- HDU 3335 解题报告
- hdu 2516解题报告
- hdu 1004解题报告
- hdu 2139解题报告
- hdu 1019解题报告
- 4619——Warm up 2
- 初级程序员是需要导师的
- Codeforces Round #192 (Div. 2)
- 删除android模拟器中的程序
- 极限优化:Haar特征的另一种的快速计算方法—boxfilter
- HDU 4606 Occupy Cities 解题报告
- imageview 边框
- POJ 1265 Area (pick定理)
- ConcurrentLinkedQueue的实现原理分析
- phpMyadmin怎么这么慢!
- 7月25日
- linux ps命令
- IOS平台下OpenCV的配置和使用
- 1002 487-3279