问题描述:
试题编号: | 201712-4 |
试题名称: | 行车路线 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明和小芳出去乡村玩,小明负责开车,小芳来导航。 输入格式 输入的第一行包含两个整数n, m,分别表示路口的数量和道路的数量。路口由1至n编号,小明需要开车从1号路口到n号路口。 输出格式 输出一个整数,表示最优路线下小明的疲劳度。 样例输入 6 7 样例输出 76 样例说明 从1走小道到2,再走小道到3,疲劳度为52=25;然后从3走大道经过4到达5,疲劳度为20+30=50;最后从5走小道到6,疲劳度为1。总共为76。 数据规模和约定 对于30%的评测用例,1 ≤ n ≤ 8,1 ≤ m ≤ 10; |
一看到这道题就想到用深度优先搜索,毕竟深搜思维简单,数据类型也没考虑。然后不出意外的超时了,30分。╮(╯﹏╰)╭
#include<iostream>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<vector>
using namespace std;
struct node
{
int d,c,t;
};
bool visited[510];
int minfati;//最小疲劳度
int totalfati;//当前正在计算的疲劳度
int totalLen;
int s=0;
int n;
vector< vector<node> > G(510);
void dfs(int i)
{
if(i==n)
{
minfati=min(minfati,totalfati);//更新最小疲劳度
return ;
}
for(int j=0;j<G[i].size();j++)
{
node r=G[i][j];
if(!visited[r.d])
{
int to0=totalfati,s0=s;
if(r.t==1)
{
s+=r.c;//小路连续
if(r.d==n) totalfati+=s*s;//小路通向终点
}
else //大路,连续的小路终结
{
totalfati+=s*s;
totalfati+=r.c ;
s=0;
}
visited[r.d]=1;
dfs(r.d);
visited[r.d]=0;
totalfati=to0;
s=s0;
}
}
}
int main()
{
int m;
cin>>n>>m;
memset(visited,0,sizeof(visited));
for(int i=0;i<m;i++)
{
int a,b;
node r1,r2;
cin>>r1.t>>a>>b>>r1.c;
r2.t=r1.t;r2.c=r1.c;r1.d=a;r2.d=b;
G[a].push_back(r2);
G[b].push_back(r1);
}
minfati=1<<30;
totalLen=0;
totalfati=0;
visited[1]=1;
dfs(1);
cout<<minfati<<endl;
}
然后就想到最优性剪枝,剪了一下提交还是30分(代码就没贴了)。还能怎么办,剪枝又不会剪,每次都超时真的烦(T▽T)
后来查到可以用Dijkstra算法求解。
Dijkstra算法如下:
(1)初始化:D(1)=0,若结点1与结点i有边直接相连,则D(i)等于边权w(1,i),否则D(i)=∞,S={1}。
(2)若﹁S=∅则结束,否则在﹁S中寻找D值最小的点i,S=S+{i},进行下一步。
(3)在﹁S中寻找i的后代j,若d(i)+w(i,j)<d(j) 则置d(j)=d(i)+w(i,j),回到第(2)步。
用来求某点到其他各点的最短距离。放在这一题求最小疲劳度岂不是有异曲同工之妙?就是边权的求法需要分情况讨论。再用一个数组记录到某结点的连续小路长。
AC代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=510;
const long long INF=1<<30;
struct node
{
int v,t;
long long c;
};
int n,m;
vector< vector<node> > G(maxn);//用邻接表来表示图
bool visited[maxn];
long long d[maxn];
long long con_trail[maxn];//记录到某结点的连续小路长
long long pow_2(long long a)
{
return a*a;
}
void Dijkstra(int i)
{
fill(d,d+maxn,INF);//将d[i]初始化为“无穷大”,fill函数在<algorithm>头文件里
d[i]=0;
for(int j=0;j<n;j++)
{
int u=-1;
long long MIN=INF;
for(int k=0;k<n;k++)
{
if(!visited[k]&&d[k]<MIN)//在非S中寻找权值最小的点
{
u=k;
MIN=d[k];
}
}
if(u==-1) return;//非S=空集
visited[u]=true;
for(int p=0;p<G[u].size();p++)
{
node r=G[u][p];
if(visited[r.v]) continue;
if(r.t ==1)//小路
{
//d[u]+w(u,v)<d[v]
if(d[u]+pow_2(con_trail[u]+r.c)-pow_2(con_trail[u])<d[r.v])
{
d[r.v]=d[u]+pow_2(con_trail[u]+r.c)-pow_2(con_trail[u]);
con_trail[r.v]=con_trail[u]+r.c;
}
}
else //大路
{
if(d[u]+r.c<d[r.v])
{
d[r.v]=d[u]+r.c ;
con_trail[r.v]=0;//连续的小路被终结
}
}
}
}
}
int main()
{
int i,a,b;
cin>>n>>m;
for(i=0;i<m;i++)
{
node n1,n2;
cin>>n1.t>>a>>b>>n1.c;
n2.t=n1.t;n2.c=n1.c;n1.v=a;n2.v=b;
G[a].push_back(n2);
G[b].push_back(n1);
}
memset(visited,0,sizeof(visited));
memset(con_trail,0,sizeof(con_trail));
Dijkstra(1);//从1号路口出发
cout<<d[n];
}