题解 城市交通(附数据)
题面
某城市 有N(1<=N<=50)个街区,某些街区由公共汽车线路相连,如在图1中,街区1,2有一条公共汽车线路相连,且由街区1至街区2的时间为34分钟。由于街区与街区之间的距离较近,与等车时间相比可忽略不记,所以这个时间为两趟公共汽车的间隔时间,即平均的等车时间。由街区1至街区5的最快走法为1-3-5,总时间为44分钟。现在市政府为了提高城市交通质量,决定加开M(1<=M<=10)条公共汽车线路。若在某两个街区A,B之间加开线路(前提是A、B之间必须已有线路),则从A到B的旅行时间缩小为原来的一半(距离未变,只是等车的时间缩短了一半)。例如,若在1,2之间加开一条线路,则时间变为17分钟,加开两条线路,时间变为8.5分钟,以此类推。所有的线路都是环路,即如果由1至2的时间变为17分钟,则由2至1的时间也变为17分钟。
求加开某些线路,能使由城市1至城市N的时间最少。例如,在图1中,如果M=2,则改变1-3,3-5的线路,总的时间可以减少为22分钟。
图一:
input:
5 2
0 34 24 0 0
34 0 10 12 0
24 10 0 16 20
0 12 16 0 30
0 0 20 30 0
output:
22.00
1 3
3 5
Dijkstra+dp
#include<bits/stdc++.h>
using namespace std;
int n,m;
double dist[51][11];
struct edge
{
int to;
double dis;
int N;
};
struct node
{
double dis;
int pos,N;
int st[11];
int en[11];
bool operator < (const node &x)const
{
return x.dis<dis;
}
};
vector<edge>a[510];
int ans1[11],ans2[11];
void Dijkstra(int x)
{
priority_queue<node>q;
for(int i=0;i<=m;i++)
{
node sta;
sta.dis=0;
sta.pos=x;
sta.N=i;
dist[x][i]=0;
q.push(sta);
}
while(!q.empty())
{
node T=q.top();
q.pop();
int now=T.pos;
for(int i=0;i<a[now].size();i++)
{
if(a[now][i].N+T.N>m)
{
continue;
}
if(dist[a[now][i].to][T.N+a[now][i].N]>dist[now][T.N]+a[now][i].dis)
{
dist[a[now][i].to][T.N+a[now][i].N]=dist[now][T.N]+a[now][i].dis;
for(int j=T.N+1;j<=T.N+a[now][i].N;j++)
{
T.st[j]=now;
T.en[j]=a[now][i].to;
}
node tmp;
tmp.dis=dist[a[now][i].to][T.N+a[now][i].N];
tmp.pos=a[now][i].to;
tmp.N=T.N+a[now][i].N;
for(int j=1;j<=m;j++)
{
tmp.st[j]=T.st[j];
tmp.en[j]=T.en[j];
}
if(tmp.pos==n&&tmp.N==m)
{
for(int k=1;k<=m;k++)
{
ans1[k]=tmp.st[k];
ans2[k]=tmp.en[k];
}
}
q.push(tmp);
}
}
}
}
int main()
{
//freopen("City.in","r",stdin);
//freopen("City.out","w",stdout);
cin>>n>>m;
double ip1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>ip1;
if(ip1)
{
for(int k=1,js=0;js<=m;k*=2,js++)
{
a[i].push_back((edge){j,ip1/k,js});
}
}
}
}
for(int i=0;i<=50;i++)
{
for(int j=0;j<=10;j++)
{
dist[i][j]=2147483647;
}
}
Dijkstra(1);
printf("%.2lf\n",dist[n][m]);
for(int i=1;i<=m;i++)
{
cout<<ans1[i]<<" "<<ans2[i]<<endl;
}
}