BZOJ1295: [SCOI2009]最长距离
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1295
windy有一块矩形土地,被分为 N*M 块 1*1 的小格子。 有的格子含有障碍物。 如果从格子A可以走到格子B,那么两个格子的距离就为两个格子中心的欧几里德距离。 如果从格子A不可以走到格子B,就没有距离。 如果格子X和格子Y有公共边,并且X和Y均不含有障碍物,就可以从X走到Y。 如果windy可以移走T块障碍物,求所有格子间的最大距离。 保证移走T块障碍物以后,至少有一个格子不含有障碍物。
100%的数据,满足 1 <= N,M <= 30 ; 0 <= T <= 30 。
题解:初看没有思路,因为不知道取掉哪些障碍物并且距离最大的点对是哪个。
然后我发现,如果不考虑t的限制,显然把 (1,1)和(n,m)之间的障碍去掉,得到最大距离。
但如果这之间的障碍数>t,那么我们就考虑下一个距离最远的点,直到它们之间的障碍数<=t,那么输出该点对之间的距离。
如何计算两点之间的障碍数呢?很简单,最短路,将点权作为权值,求最短路。
多源最短路?floyed?TLE NO 我们做n次floyed即可。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 1000 26 27 #define maxm 500+100 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 #define num(i,j) ((i-1)*m+j) 45 #define sqr(x) (x)*(x) 46 47 using namespace std; 48 49 inline int read() 50 51 { 52 53 int x=0,f=1;char ch=getchar(); 54 55 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 56 57 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 58 59 return x*f; 60 61 } 62 int n,m,t,tot,cnt,d[maxn][maxn],a[maxn],head[maxn]; 63 const int dx[4]={0,0,1,-1}; 64 const int dy[4]={1,-1,0,0}; 65 bool v[maxn]; 66 struct edge{int go,next;}e[4*maxn]; 67 struct rec{double x;int y;}b[maxn*maxn]; 68 priority_queue<pa,vector<pa>,greater<pa> >q; 69 inline void insert(int x,int y) 70 { 71 e[++tot].go=y;e[tot].next=head[x];head[x]=tot; 72 } 73 inline void dijkstra(int s) 74 { 75 for1(i,n*m)d[s][i]=inf,v[i]=0; 76 d[s][s]=a[s]; 77 q.push(pa(d[s][s],s)); 78 while(!q.empty()) 79 { 80 int x=q.top().second;q.pop();if(v[x])continue;v[x]=1; 81 for(int i=head[x],y;i;i=e[i].next) 82 if(d[s][x]+a[y=e[i].go]<d[s][y]) 83 { 84 d[s][y]=d[s][x]+a[y]; 85 q.push(pa(d[s][y],y)); 86 } 87 } 88 } 89 inline bool cmp(rec a,rec b){return a.x>b.x;} 90 91 int main() 92 93 { 94 95 freopen("input.txt","r",stdin); 96 97 freopen("output.txt","w",stdout); 98 99 n=read();m=read();t=read(); 100 for1(i,n*m) 101 { 102 char ch=' '; 103 while(ch!='0'&&ch!='1')ch=getchar(); 104 a[i]=ch-'0'; 105 } 106 for1(i,n) 107 for1(j,m) 108 for0(k,3) 109 { 110 int ii=i+dx[k],jj=j+dy[k]; 111 if(ii<1||ii>n||jj<1||jj>m)continue; 112 insert(num(i,j),num(ii,jj)); 113 } 114 for1(i,n*m)dijkstra(i); 115 for1(i,n) 116 for1(j,m) 117 for1(ii,n) 118 for1(jj,m) 119 b[++cnt].x=sqrt(sqr(i-ii)+sqr(j-jj)),b[cnt].y=d[num(i,j)][num(ii,jj)]; 120 sort(b+1,b+cnt+1,cmp); 121 int ans=1; 122 while(b[ans].y>t)ans++; 123 printf("%.6f\n",b[ans].x); 124 125 return 0; 126 127 }
UPD:看题解发现b数组不用存下来排序,暴力枚举更新答案即可。
代码:
1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13 #include<vector> 14 15 #include<map> 16 17 #include<set> 18 19 #include<queue> 20 21 #include<string> 22 23 #define inf 1000000000 24 25 #define maxn 1000 26 27 #define maxm 500+100 28 29 #define eps 1e-10 30 31 #define ll long long 32 33 #define pa pair<int,int> 34 35 #define for0(i,n) for(int i=0;i<=(n);i++) 36 37 #define for1(i,n) for(int i=1;i<=(n);i++) 38 39 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 40 41 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 42 43 #define mod 1000000007 44 #define num(i,j) ((i-1)*m+j) 45 #define sqr(x) (x)*(x) 46 47 using namespace std; 48 49 inline int read() 50 51 { 52 53 int x=0,f=1;char ch=getchar(); 54 55 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 56 57 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 58 59 return x*f; 60 61 } 62 int n,m,t,tot,cnt,d[maxn][maxn],a[maxn],head[maxn]; 63 const int dx[4]={0,0,1,-1}; 64 const int dy[4]={1,-1,0,0}; 65 bool v[maxn]; 66 struct edge{int go,next;}e[4*maxn]; 67 priority_queue<pa,vector<pa>,greater<pa> >q; 68 inline void insert(int x,int y) 69 { 70 e[++tot].go=y;e[tot].next=head[x];head[x]=tot; 71 } 72 inline void dijkstra(int s) 73 { 74 for1(i,n*m)d[s][i]=inf,v[i]=0; 75 d[s][s]=a[s]; 76 q.push(pa(d[s][s],s)); 77 while(!q.empty()) 78 { 79 int x=q.top().second;q.pop();if(v[x])continue;v[x]=1; 80 for(int i=head[x],y;i;i=e[i].next) 81 if(d[s][x]+a[y=e[i].go]<d[s][y]) 82 { 83 d[s][y]=d[s][x]+a[y]; 84 q.push(pa(d[s][y],y)); 85 } 86 } 87 } 88 89 int main() 90 91 { 92 93 freopen("input.txt","r",stdin); 94 95 freopen("output.txt","w",stdout); 96 97 n=read();m=read();t=read(); 98 for1(i,n*m) 99 { 100 char ch=' '; 101 while(ch!='0'&&ch!='1')ch=getchar(); 102 a[i]=ch-'0'; 103 } 104 for1(i,n) 105 for1(j,m) 106 for0(k,3) 107 { 108 int ii=i+dx[k],jj=j+dy[k]; 109 if(ii<1||ii>n||jj<1||jj>m)continue; 110 insert(num(i,j),num(ii,jj)); 111 } 112 for1(i,n*m)dijkstra(i); 113 double ans=0.0; 114 for1(i,n) 115 for1(j,m) 116 for1(ii,n) 117 for1(jj,m) 118 if(d[num(i,j)][num(ii,jj)]<=t)ans=max(ans,sqrt(sqr(i-ii)+sqr(j-jj))); 119 printf("%.6f\n",ans); 120 121 return 0; 122 123 }
还有此题SPFA貌似更快?不过好像是网格图唉。。。