hdu4606:http://acm.hdu.edu.cn/showproblem.php?pid=4606
题意:在一个二维坐标系中,有n个城市,坐标给出来了,然后有p个士兵要去占领这n个城市,但是路上有m个路障,都是线段,士兵不能越过路障前进。
每个士兵都有相同容量大小的一个干粮袋,每到一个城市他就能补充满自己的干粮袋。中途走路时走一个单位长度就消耗一个单位的干粮。
现在问的是这些个干粮袋最小的容量是多少,前提是保证p个士兵能占领完这n个城市,城市被占领顺序也是题目给好的,必须遵守。
题解:这一题是一道很好的综合题。首先一点,就是求出任意两个城市的最短距离。这个也是我今天学到的知识。我们可以把障碍的端点当做2个点,如果城市i和城市j之间没有障碍的话,那么i,j之间的距离就可以直接算出。如果有障碍的话,就只能绕过障碍的端点来求。怎么求呢?只要把端点当做路径上的点就可以了,然后用floyd过一遍即可。这里,要用到判断两条线段是否相交的。然后可以联想到的是最小点覆盖。但是这里的是最小点覆盖小于p都是满足的。所以接下来可以二分枚举长度,找到最小额满足条件的长度。用到二分以及二分图的最大匹配。因为最小点覆盖==点数--二分图的最大匹配。还有一个就序列,这也是要考虑。这里只哎哟我们建图的时候,让前面的序列指向后面的序列就可以了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 using namespace std; 7 const double inf=1000000000.0; 8 int n,m,p; 9 int seq[600],cy[600]; 10 double g[600][600]; 11 bool key[600][600],visit[600]; 12 struct point{ 13 double x,y; 14 }dian[602]; 15 struct Node{ 16 point a; 17 point b; 18 }xian[602]; 19 double dis(int a,int b){ 20 return sqrt((dian[a].x-dian[b].x)*(dian[a].x-dian[b].x)+(dian[a].y-dian[b].y)*(dian[a].y-dian[b].y)); 21 22 } 23 double Cross( point a, point b, point o){ 24 return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); 25 } 26 bool IsIntersect( Node u, Node v){ 27 return (Cross(v.a, u.b, u.a) * Cross(u.b, v.b, u.a) > 0) && 28 (Cross(u.a, v.b, v.a) * Cross(v.b, u.b, v.a) > 0) && 29 (max(u.a.x, u.b.x) > min(v.a.x, v.b.x)) && 30 (max(v.a.x, v.b.x) > min(u.a.x, u.b.x)) && 31 (max(u.a.y, u.b.y) > min(v.a.y, v.b.y)) && 32 (max(v.a.y, v.b.y) > min(u.a.y, u.b.y)); 33 } 34 35 bool judge(int a,int b){ 36 for(int i=1;i<=m;i++){ 37 if((a+1-n)/2==i&&(b+1-n)/2==i)continue; 38 Node temp;temp.a=dian[a];temp.b=dian[b]; 39 if(IsIntersect(temp,xian[i])) 40 return false; 41 } 42 return true; 43 } 44 int path(int u){ 45 for(int i=1;i<=n;i++){ 46 if(!visit[i]&&key[u][i]){ 47 visit[i]=1; 48 if(cy[i]==-1||path(cy[i])){ 49 cy[i]=u; 50 return 1; 51 } 52 } 53 } 54 return 0; 55 } 56 int maxmatch(){ 57 memset(cy,-1,sizeof(cy)); 58 int res=0; 59 for(int i=1;i<=n;i++){ 60 memset(visit,0,sizeof(visit)); 61 res+=path(i); 62 } 63 return res; 64 } 65 bool task(double mid){ 66 memset(key,0,sizeof(key)); 67 for(int i=1;i<=n;i++) 68 for(int j=1;j<=n;j++){ 69 if(g[i][j]<=mid&&seq[i]<seq[j]) 70 key[i][j]=1; 71 } 72 int as=maxmatch(); 73 if(n-as<=p)return true; 74 else return false; 75 } 76 77 double solve(){ 78 double l=0,r=inf,ans=0; 79 while(abs(l-r)>0.0000001){ 80 double mid=(l+r)/2; 81 if(task(mid)){ 82 ans=mid; 83 r=mid; 84 } 85 else 86 l=mid; 87 } 88 return ans; 89 } 90 int temp; 91 int main(){ 92 int cas; 93 scanf("%d",&cas); 94 while(cas--){ 95 scanf("%d%d%d",&n,&m,&p); 96 memset(g,0,sizeof(g)); 97 for(int i=1;i<=n;i++){ 98 scanf("%lf%lf",&dian[i].x,&dian[i].y); 99 } 100 for(int i=1;i<=m;i++){ 101 scanf("%lf %lf",&xian[i].a.x,&xian[i].a.y); 102 dian[i*2+n-1].x=xian[i].a.x; 103 dian[i*2+n-1].y=xian[i].a.y; 104 scanf("%lf %lf",&xian[i].b.x,&xian[i].b.y); 105 dian[i*2+n].x=xian[i].b.x; 106 dian[i*2+n].y=xian[i].b.y; 107 } 108 memset(seq,0,sizeof(seq)); 109 for(int i=1;i<=n;i++){ 110 scanf("%d",&temp); 111 seq[temp]=i; 112 } 113 for(int i=1;i<=n+2*m;i++){ 114 for(int j=1;j<=n+2*m;j++){ 115 if(j==i)continue; 116 if(judge(i,j)){ 117 g[i][j]=dis(i,j); 118 } 119 else 120 g[i][j]=inf; 121 } 122 g[i][i]=inf; 123 } 124 for(int k=1;k<=n+2*m;k++) 125 for(int i=1;i<=n+2*m;i++) 126 for(int j=1;j<=n+2*m;j++) 127 g[i][j]=min(g[i][j],g[i][k]+g[k][j]); 128 double ans=0; 129 ans=solve(); 130 printf("%.2f ",ans); 131 } 132 }