POJ 1511 图论入门第九题

    技术2022-05-20  45

         题目大意:这道题描述非常的蛋疼、英语不好读了几遍才懂。就是说求原点到所有点的最短距离+该点到原点的最短距离。

         题目分析:如果不加任何剪枝直接spfa的话会超时,题目给了8000ms但依然不够。我使用邻接表来存储图、并反向建立表,这样我们遍历图两遍(正、反)就可以求解出此题。不过这题的建图我一开始不会。参考了一位大牛的方法、图的邻接表写法真是各式各样啊,每一种写法都能解决不同的问题。何时哥才能达到那种境界啊!啊 ? 啊 ?!

         另外注意,这题可能会中间溢出(我定义了unsigned long long),所以对于变量的处理一定要谨慎。

         代码:

     

    #include<cstdio> #include<cstring> #include<queue> #include<algorithm> using namespace std; #define init(a,what) memset(a,what,sizeof(a)) #define read freopen("zx.in","r",stdin) #define write freopen("zx.out","w",stdout) const int INF=0x3f3f3f3f; const int MAXN=1000000+10; typedef unsigned long long int64; typedef struct { int v,next,cost; }ZX;//邻接表存图 ZX zx1[MAXN],zx2[MAXN]; int nnum,mnum,ans; int64 sumdist,dist[MAXN],p1[MAXN],p2[MAXN]; void read_G(int a,int b,int c) { //将图反向建立一遍,可得任何点到原点的最短路(有向图) ans++; zx1[ans].v=b, zx1[ans].next=p1[a], zx1[ans].cost=c, p1[a]=ans; zx2[ans].v=a, zx2[ans].next=p2[b], zx2[ans].cost=c, p2[b]=ans; } void spfa(int64 *p,ZX e[]) { queue<int>q; bool vis[MAXN]; init(vis,false); while(!q.empty()) q.pop(); for(int i=1;i<=nnum;i++) dist[i]=(i==1 ? 0 : INF); q.push(1); vis[1]=true; while(!q.empty()) { int xx=q.front(); q.pop(); vis[xx]=false; for(int i=p[xx];i!=0;i=e[i].next) { if(dist[e[i].v]>dist[xx]+e[i].cost) { dist[e[i].v]=dist[xx]+e[i].cost; if(!vis[e[i].v]) { vis[e[i].v]=true; q.push(e[i].v); } } } } } int main() { read, write; int ncase; scanf("%d",&ncase); while(ncase--) { ans=0; init(p1,0); init(p2,0); scanf("%d%d",&nnum,&mnum); for(int i=1;i<=mnum;i++) { int a,b,cost; scanf("%d%d%d",&a,&b,&cost); read_G(a,b,cost); } sumdist=0; spfa(p1,zx1);//正向遍历一遍可求得原点到任意点的最短路 for(int i=1;i<=nnum;i++) sumdist+=dist[i]; spfa(p2,zx2);//反向遍历求任意点到远点的最短路 for(int i=1;i<=nnum;i++) sumdist+=dist[i]; printf("%I64d/n",sumdist); } return 0; }


    最新回复(0)