P4162 [SCOI2009]最长距离
这道题数据范围比较小,所以方法还是比较暴力的。
思路:
先按每个格子的状态,让所有格子与他周围的格子连一条权值为它连向那个格子的值(0或1)。然后我们n方枚举所有格子跑最短路,最短路即为从起点到终点的最小障碍数。然后我们枚举所有最短路,先看他移除障碍后是否只用了小于等于k次机会,然后求出两点间的距离,取max即可。
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; struct node{ int nxt,to,val; }edge[maxn*3]; int head[maxn],cnt; int num[550][550]; int val[550][550]; char s[550][550]; int n,m,t; void add(int x,int y,int v){ edge[++cnt].nxt=head[x]; edge[cnt].to=y; edge[cnt].val=v; head[x]=cnt; } priority_queue<pair<int ,int> >q; double dist(int x,int y,int xx,int yy){ return (double)sqrt((x-xx)*(x-xx)*1.0+(y-yy)*(y-yy)*1.0); } double ans; bool vis[maxn]; int dis[maxn]; void dijkstra(int x){ memset(dis,88,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[x]=0; q.push(make_pair(0,x)); while(q.size()){ int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=true; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(dis[v]>dis[u]+edge[i].val){ dis[v]=dis[u]+edge[i].val; q.push(make_pair(-dis[v],v)); } } } } int main(){ scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ cin>>s[i][j]; num[i][j]=(i-1)*m+j; if(s[i][j]=='1') val[i][j]=1; } } /* for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ printf("%d ",num[i][j]); } printf("\n"); }*/ for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(i>1) add(num[i][j],num[i-1][j],val[i-1][j]); if(i<n) add(num[i][j],num[i+1][j],val[i+1][j]); if(j>1) add(num[i][j],num[i][j-1],val[i][j-1]); if(j<m) add(num[i][j],num[i][j+1],val[i][j+1]); } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ dijkstra(num[i][j]); for(int x=1;x<=n;x++){ for(int y=1;y<=m;y++){ if(dis[num[x][y]]+val[i][j]<=t) ans=max(ans,dist(i,j,x,y)); } } } } printf("%.6lf\n",ans); return 0; }