Codeforces Round #333 (Div. 2) C. The Two Routes
- 题意:有V个村庄,每两个村庄间都有路(铁路或公路,铁路和公路不重合,也就是说有铁路就没有公路),其中铁路有E条,让我们求从村庄1到村庄V的最短路径。如果沿着铁路走到不了或者沿着公路走到不了都输出-1,如果沿着铁路走和沿着公路走其各自最短路径的时间不一样,那就输出较大者。所有路径的边权都为1。
- 思路:就是跑两个最短路的模板就可以了。就是要注意一下处理好边的情况就可以了,我这里是用的邻接矩阵来判断是不是铁路。
SPFA:
刚刚知道SPFA的一个小优化,就是用stack(后进后出)代替queue(后进前出),会优化一点,十几ms,至于为什么我也不知道,可能是因为后进后出的话会先遍历完所有的点,所以会尽可能地减少重复入队的可能叭。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxV=405;
const int maxE=8e4;
int V,E;
bool mp[maxV][maxV];
bool T_inque[maxV],G_inque[maxV];
int T_dis[maxV],G_dis[maxV];
int T_head[maxV],G_head[maxV],T_cnt,G_cnt;
struct EDGE{
int pre,to;
EDGE(int a=0,int b=0):pre(a),to(b){}
};
EDGE T_edge[2*maxE];
EDGE G_edge[2*maxE];
void T_add_edge(int u,int v)
{
T_edge[++T_cnt]=EDGE(T_head[u],v);
T_head[u]=T_cnt;
}
void G_add_edge(int u,int v)
{
G_edge[++G_cnt]=EDGE(G_head[u],v);
G_head[u]=G_cnt;
}
void init()
{
T_cnt=0;
G_cnt=0;
memset(mp, false, sizeof(mp));
memset(T_head,-1, sizeof(T_head));
memset(G_head,-1, sizeof(G_head));
}
int T_SPFA(int st,int ed)
{
for(int i=1;i<=V;i++)
T_dis[i]=(i==st ? 0 : INF);
memset(T_inque,false, sizeof(T_inque));
stack<int >s;
s.push(st);
T_inque[st]=true;
while(!s.empty())
{
int tmp=s.top();
s.pop();
for(int i=T_head[tmp]; ~i ; i=T_edge[i].pre)
{
if(T_dis[T_edge[i].to]>T_dis[tmp]+1)
{
T_dis[T_edge[i].to]=T_dis[tmp]+1;
if(!T_inque[T_edge[i].to])
{
s.push(T_edge[i].to);
T_inque[T_edge[i].to]=true;
}
}
}
T_inque[tmp]= false;
}
return T_dis[ed];
}
int G_SPFA(int st,int ed)
{
for(int i=1;i<=V;i++)
G_dis[i]=(i==st ? 0 : INF);
memset(G_inque,false, sizeof(G_inque));
stack<int >s;
s.push(st);
G_inque[st]=true;
while(!s.empty())
{
int tmp=s.top();
s.pop();
for(int i=G_head[tmp]; ~i ; i=G_edge[i].pre)
{
if(G_dis[G_edge[i].to]>G_dis[tmp]+1)
{
G_dis[G_edge[i].to]=G_dis[tmp]+1;
if(!G_inque[G_edge[i].to])
{
s.push(G_edge[i].to);
G_inque[G_edge[i].to]=true;
}
}
}
G_inque[tmp]= false;
}
return G_dis[ed];
}
int main()
{
while(~scanf("%d%d",&V,&E))
{
init();
for(int i=1;i<=E;i++)
{
int a,b;
scanf("%d%d",&a,&b);
T_add_edge(min(a,b),max(a,b));
T_add_edge(max(a,b),min(a,b));
mp[min(a,b)][max(a,b)]=true;
}
for(int i=1;i<=V;i++)
for(int j=i+1;j<=V;j++)
if(!mp[i][j])
{
G_add_edge(i,j);
G_add_edge(j,i);
}
int GE=V*(V-1)/2-E;
int ansT,ansG;
if(GE==0||(ansT=T_SPFA(1,V))==INF||(ansG=G_SPFA(1,V))==INF)
printf("-1\n");
else
printf("%d\n",max(ansT,ansG));
}
return 0;
}
Dijkstra【链式前向星】:
做了个小小的优化:dij终点取出来就可以直接return了。
然后今天发现dij有些概念模糊叭,反正就是又模拟了一遍dij,重新理解了一下。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define P(x) x>0?x:0
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxV=405;
const int maxE=8e4;
int V,E;
bool mp[maxV][maxV];
struct EDGE{
int pre,to;
EDGE(int a=0,int b=0):pre(a),to(b){}
};
EDGE T_edge[maxE*2],G_edge[maxE*2];
int T_head[maxV],G_head[maxV],T_cnt,G_cnt;
int T_dis[maxV],G_dis[maxV];
bool T_vis[maxV],G_vis[maxV];
void T_add_edge(int u,int v)
{
T_edge[++T_cnt]=EDGE(T_head[u],v);
T_head[u]=T_cnt;
}
void G_add_edge(int u,int v)
{
G_edge[++G_cnt]=EDGE(G_head[u],v);
G_head[u]=G_cnt;
}
void init()
{
T_cnt=0;
G_cnt=0;
memset(T_head,-1, sizeof(T_head));
memset(G_head,-1, sizeof(G_head));
memset(mp,false, sizeof(mp));
}
struct node{
int point,val;
node(int a=0,int b=0):point(a),val(b){}
friend bool operator < (node n1,node n2) { return n1.val>n2.val; }
};
int T_dijkstra(int st,int ed)
{
memset(T_vis,false,sizeof(T_vis));
for(int i=1;i<=V;i++)
T_dis[i]=(i==st ? 0 : INF);
priority_queue<node>pq;
pq.push(node(st,T_dis[st]));
while(!pq.empty())
{
node tmp=pq.top();
if(tmp.point==ed)
return T_dis[ed];
if(T_vis[tmp.point])
continue;
pq.pop();
T_vis[tmp.point]=true;
for(int i=T_head[tmp.point]; ~i ; i=T_edge[i].pre)
{
if(T_dis[T_edge[i].to]>T_dis[tmp.point]+1)
{
T_dis[T_edge[i].to]=T_dis[tmp.point]+1;
pq.push(node(T_edge[i].to,T_dis[T_edge[i].to]));
}
}
}
return -1;
}
int G_dijkstra(int st,int ed)
{
memset(G_vis,false,sizeof(G_vis));
for(int i=1;i<=V;i++)
G_dis[i]=(i==st ? 0 : INF);
priority_queue<node>pq;
pq.push(node(st,G_dis[st]));
while(!pq.empty())
{
node tmp=pq.top();
if(tmp.point==ed)
return G_dis[ed];
if(G_vis[tmp.point])
continue;
pq.pop();
G_vis[tmp.point]=true;
for(int i=G_head[tmp.point]; ~i ; i=G_edge[i].pre)
{
if(G_dis[G_edge[i].to]>G_dis[tmp.point]+1)
{
G_dis[G_edge[i].to]=G_dis[tmp.point]+1;
pq.push(node(G_edge[i].to,G_dis[G_edge[i].to]));
}
}
}
return -1;
}
int main()
{
while(~scanf("%d%d",&V,&E))
{
init();
for(int i=1;i<=E;i++)
{
int a,b;
scanf("%d%d",&a,&b);
T_add_edge(a,b);
T_add_edge(b,a);
mp[min(a,b)][max(a,b)]=true;
}
for(int i=1;i<=V;i++)
for(int j=i+1;j<=V;j++)
if(!mp[i][j])
{
G_add_edge(i,j);
G_add_edge(j,i);
}
int GE=V*(V-1)/2-E;
int ansT,ansG;
if(GE==0||(ansT=T_dijkstra(1,V))==-1||(ansG=G_dijkstra(1,V))==-1)
printf("-1\n");
else
printf("%d\n",max(ansT,ansG));
}
return 0;
}
Djikstra【邻接矩阵】
这个题的话,其实是个稠密图,用链式前向星的话空间占据其实很大,也比较麻烦,时间优势差不多也没有多少。这时候用邻接矩阵就比较合适,省空间,也比较好写,一哈就写出来了。(听别人的建议所以补上的,确实比上面两个代码短也合适)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define P(x) x>0 ? x : 0
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
using namespace std;
typedef long long ll;
typedef vector<int>:: iterator VITer;
const int maxN=405;
int mp[maxN][maxN],dis[maxN],vis[maxN];
int n,m;
struct node{
int to,val;
node(int a=0,int b=0):to(a),val(b){}
friend bool operator < (node n1,node n2) { return n1.val>n2.val; }
};
int dijkstra(int st,int ed,int road)//铁路是1,公路是0
{
memset(vis,0, sizeof(vis));
for(int i=1;i<=n;i++)
dis[i]=(i==st ? 0 : INF);
priority_queue<node>pq;
pq.push(node(st,dis[st]));
while(!pq.empty())
{
node tmp=pq.top();
pq.pop();
if(vis[tmp.to])
continue;
for(int i=1;i<=n;i++)
{
if(mp[tmp.to][i]!=-1)
{
if(road && mp[tmp.to][i])//铁路
{
if(dis[i]>dis[tmp.to]+1)
{
dis[i]=dis[tmp.to]+1;
pq.push(node(i,dis[i]));
}
}
else if(!road && !mp[tmp.to][i])//公路
{
if(dis[i]>dis[tmp.to]+1)
{
dis[i]=dis[tmp.to]+1;
pq.push(node(i,dis[i]));
}
}
}
}
vis[tmp.to]=1;
}
return dis[ed];
}
void init()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j)
mp[i][j]=-1;
else
mp[i][j]=0;
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=m;i++)
{
int a,b; scanf("%d%d",&a,&b);
mp[a][b]=1;
mp[b][a]=1;
}
int T=dijkstra(1,n,1);
int G=dijkstra(1,n,0);
if(T==INF||G==INF)
printf("-1\n");
else
printf("%d\n",max(T,G));
}
return 0;
}
My_Feeling:
- 过这道题用了5h+,QAQ,tcl,真的醉了,还好今天休息,不然我要疯了,还要哭了QAQ,这道题可是排位赛的时候有人半小时过了的,我做了那么久,tcl,我tcl
- 最开始的时候敲的是SPFA,后来交了之后CE?????什么情况??????开始的时候多敲了一部分并查集,因为开始题意搞错了,所以用了并查集,后来又读了一遍发现理解错了,用不到,但是没删就交了,于是CE?????我把它删了之后就没有CE了???跟这个有关系吗?它开始running了,然后T在了54组样例,当时还忘记了CF可以看错误样例。就先去吃了个饭,吃饭的时候还重新算了下时间复杂度,在范围内啊,但还是怕就卡了时间叭。然后知道用stack可以优化SPFA,于是试了一下,发现还是T在了54组。于是我就坚信它是卡了时间,于是我就又敲了一遍Dijkstra,然后20组就T了???????什么情况。然后又到处优化了点小地方之后还是一样的T在了20组。
- 然后!!就突然灵光闪现想起可以看错误样例,然后看了下第54组,发现【第一行400 1】【第二行1 400】,然后就开始调试,发现CLion报错,运行不了????是哪里的问题,找了半天没找出来,看了下数组也开够了,但是就是运行不了?????后来我就想(小心思不可取):把这组样例特判一下,本来是放在了处理完了G_edge[ ]的后面,然后发现还是不能跑,然后我又换在了那个for循环的前面然后交了,!竟然真的给过了……然后又开始debug,发现还是有的地方不能跑,出现了问题,CLion报错。到底是哪里???哎,好崩溃。后来的后来的后来,我发现我跑mp [ ][ ]的点跑错了,我(1,1)(2,2)这种点也跑了,所以数组溢出了QAQ,我的天呐!!!怪不得之前第一发CE了!QAQ……然后我就交了,然后SPFA就过了。
- 我的那个Dijkstra也是跟SPFA一样跑了(1,1)这种点,然后改了这里之后发现还是不能跑,????调试的时候发现T_head[ ],莫名其妙出现了G_head[ ]里面的值,开始的时候没有,到后来的时候就有了,为什么???又是后来的后来,我发现QAQ我的G_edge[ ]数组少开了一倍,我哭!!!啊啊啊,然后改了之后果然也过了
- 其实我的经历远不止这些,五个小时啊!QAQ,反正就各种错误叭。tcl