ZOJ3460 Missile(神奇的建图)
2016-02-14 15:07
253 查看
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3460
感叹出题人的脑洞。。。
这里把第i个基地第j次发射导弹这一事件记作点(j-1)*N+i,这样就成功处理了分次发射导弹的问题。。每个点都和目标相连,边权为所花的时间,即:j*T1+(j-1)*T2+d/V,然后二分时间限制。求二分匹配时如果对应边的权大于时间限制就不选此边,然后看最大匹配数是否等于m,若否则增大时间限;否则减小时间限。直到这一次与上一次的时间限小于1e-6,既达到目标精度。。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define N 55
#define M 2510
#define eps 1e-8
#define INF 200000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define d(x,y) sqrt((x)*(x)+(y)*(y))
double G
[M],limit,A
[2],B[M][2];
bool vis[M];
int Nx,Ny,Mx
,My[M],dx
,dy[M],dis;
bool bfs(){
queue<int> q;dis=INF;int u;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=Nx;++i){
if(Mx[i]==-1){q.push(i);dx[i]=0;}
}
while(!q.empty()){
u=q.front();q.pop();
if(dx[u]>dis) break;
for(int i=1;i<=Ny;++i){
if(G[u][i]<=limit&&dy[i]==-1){
dy[i]=dx[u]+1;
if(My[i]==-1) dis=dy[i];
else{
dx[My[i]]=dy[i]+1;q.push(My[i]);
}
}
}
}
return dis!=INF;
}
bool dfs(int u){
for(int i=1;i<=Ny;++i){
if(G[u][i]<=limit&&!vis[i]&&dy[i]==dx[u]+1){
vis[i]=true;
if(My[i]!=-1&&dy[i]==dis) continue;
if(My[i]==-1||dfs(My[i])){
My[i]=u;Mx[u]=i;return true;
}
}
}
return false;
}
int MaxMatch(){
int ans=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(bfs()){
memset(vis,false,sizeof(vis));
for(int i=1;i<=Nx;++i){
if(Mx[i]==-1&&dfs(i)) ++ans;
}
}
return ans;
}
int main(){
int n,m,ans;double L,R,T1,T2,v;
while(scanf("%d%d%lf%lf%lf",&n,&m,&T1,&T2,&v)!=EOF){
L=INF;R=-INF;Nx=m;Ny=n*m;T1=T1/60;
for(int i=1;i<=m;++i) scanf("%lf%lf",&A[i][0],&A[i][1]);
for(int i=1;i<=n;++i){
scanf("%lf%lf",&B[i][0],&B[i][1]);
for(int j=1;j<=m;++j){
G[j][i]=d(A[j][0]-B[i][0],A[j][1]-B[i][1])/v+T1;
L=min(L,G[j][i]);R=max(R,G[j][i]);
for(int k=1;k<m;++k){
G[j][k*n+i]=G[j][i]+(T1+T2)*k;
L=min(L,G[j][k*n+i]);R=max(R,G[j][k*n+i]);
}
}
}
while(R-L>eps){
limit=(L+R)/2;
ans=MaxMatch();
if(ans==m) R=limit;
else L=limit;
}
printf("%.6lf\n",limit);
}
return 0;
}
感叹出题人的脑洞。。。
这里把第i个基地第j次发射导弹这一事件记作点(j-1)*N+i,这样就成功处理了分次发射导弹的问题。。每个点都和目标相连,边权为所花的时间,即:j*T1+(j-1)*T2+d/V,然后二分时间限制。求二分匹配时如果对应边的权大于时间限制就不选此边,然后看最大匹配数是否等于m,若否则增大时间限;否则减小时间限。直到这一次与上一次的时间限小于1e-6,既达到目标精度。。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define N 55
#define M 2510
#define eps 1e-8
#define INF 200000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define d(x,y) sqrt((x)*(x)+(y)*(y))
double G
[M],limit,A
[2],B[M][2];
bool vis[M];
int Nx,Ny,Mx
,My[M],dx
,dy[M],dis;
bool bfs(){
queue<int> q;dis=INF;int u;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(int i=1;i<=Nx;++i){
if(Mx[i]==-1){q.push(i);dx[i]=0;}
}
while(!q.empty()){
u=q.front();q.pop();
if(dx[u]>dis) break;
for(int i=1;i<=Ny;++i){
if(G[u][i]<=limit&&dy[i]==-1){
dy[i]=dx[u]+1;
if(My[i]==-1) dis=dy[i];
else{
dx[My[i]]=dy[i]+1;q.push(My[i]);
}
}
}
}
return dis!=INF;
}
bool dfs(int u){
for(int i=1;i<=Ny;++i){
if(G[u][i]<=limit&&!vis[i]&&dy[i]==dx[u]+1){
vis[i]=true;
if(My[i]!=-1&&dy[i]==dis) continue;
if(My[i]==-1||dfs(My[i])){
My[i]=u;Mx[u]=i;return true;
}
}
}
return false;
}
int MaxMatch(){
int ans=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(bfs()){
memset(vis,false,sizeof(vis));
for(int i=1;i<=Nx;++i){
if(Mx[i]==-1&&dfs(i)) ++ans;
}
}
return ans;
}
int main(){
int n,m,ans;double L,R,T1,T2,v;
while(scanf("%d%d%lf%lf%lf",&n,&m,&T1,&T2,&v)!=EOF){
L=INF;R=-INF;Nx=m;Ny=n*m;T1=T1/60;
for(int i=1;i<=m;++i) scanf("%lf%lf",&A[i][0],&A[i][1]);
for(int i=1;i<=n;++i){
scanf("%lf%lf",&B[i][0],&B[i][1]);
for(int j=1;j<=m;++j){
G[j][i]=d(A[j][0]-B[i][0],A[j][1]-B[i][1])/v+T1;
L=min(L,G[j][i]);R=max(R,G[j][i]);
for(int k=1;k<m;++k){
G[j][k*n+i]=G[j][i]+(T1+T2)*k;
L=min(L,G[j][k*n+i]);R=max(R,G[j][k*n+i]);
}
}
}
while(R-L>eps){
limit=(L+R)/2;
ans=MaxMatch();
if(ans==m) R=limit;
else L=limit;
}
printf("%.6lf\n",limit);
}
return 0;
}
相关文章推荐
- 简单的四则运算
- 数的奇偶性
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- 快速排序里的学问:从猜数字开始
- 矩阵的乘法操作
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂
- HDOJ 1002 A + B Problem II (Big Numbers Addition)
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1002
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006