POJ 1511 Invitation Cards【SPFA】
http://poj.org/problem?id=1511
POJ 1511 Invitation Cards
大意:求有向图中从源点到每个节点的往返距离和
分析:
1.根据题意建立两幅图,分别对应于正向图和反向图
2.分别对正向图和反向图求从源点即题中的1结点出发求単源最短路径,
3. 由2易得,正向图中求得的dis[i]为s到i的最短路,反向图中求得的dis[i]为i到s的最短路
那么s到i的往返距离即为两个dis相加
4.在求単源最短路时用SPFA,两次SPFA即可完成
重点注意:需要读入的数据较大,使用getint()函数可大大减少读数据时间
View Code
1 #include<stdio.h>
2 #include<string.h>
3 #include<queue>
4 #include<iostream>
5 usingnamespace std;
6 constint N =1000000+5;//顶点个数
7 struct EDGE
8 {
9 long v;
10 long price;
11 EDGE *next;
12 }edges[2][N],*ind[2][N];//使用指针实现邻接表的存储
13
14 __int64 dis[N];
15 int ednum;//记录边数
16 bool isInQueue[N];//isInQueue[i]标记i当前是否在队列中
17 void spfa(int eid,int sid,int n)//spfa求eid图中从sid出发的単源最短路径
18 {
19 queue<int>myQueue;
20 int i,j;
21 for(i=1;i<=n;i++)
22 {
23 dis[i]=-1;
24 isInQueue[i]=false;
25 }
26
27 int cur;
28 cur = sid;
29 dis[cur]=0;
30 isInQueue[cur]=true;
31 myQueue.push(cur);
32
33 while(!myQueue.empty())
34 {
35 cur = myQueue.front();//每次仅对队列中的点进行松弛操作
36 myQueue.pop();
37 isInQueue[cur]=false;
38 for(EDGE *p = ind[eid][cur];p;p=p->next)
39 {
40 __int64 temp = p->price+dis[cur];
41 if(dis[p->v]==-1||temp<dis[p->v])
42 {
43 dis[p->v]=temp;
44 if(isInQueue[p->v]==false)
45 {
46 myQueue.push(p->v);
47 isInQueue[p->v]=true;
48 }
49 }
50 }
51
52 }
53
54 }
55
56 //添加新边
57 inline void addEdge(long a,long b,long c)
58 {
59 EDGE *po,*op;
60 po =&edges[0][ednum];//正向边
61 op =&edges[1][ednum];//反向边
62 ednum++;
63
64 po->price = c;
65 po->v = b;
66 po->next = ind[0][a];
67 ind[0][a]=po;
68
69 op->price = c;
70 op->v = a;
71 op->next = ind[1][b];
72 ind[1][b]=op;
73
74 }
75
76 inline long getint() //这个getchar的输入对大数据量输入非常有用,甚至可以挽救效率不高的算法
77 {
78 long ret=0;
79 char tmp;
80 while(!isdigit(tmp=getchar()));
81 do{
82 ret=(ret<<3)+(ret<<1)+tmp-'0';
83 }while(isdigit(tmp=getchar()));
84 return ret;
85 }
86
87 int main()
88 {
89 int T;
90 while(scanf("%d",&T)!=EOF)
91 {
92 while(T--)
93 {
94 int P,Q;
95 scanf("%d%d",&P,&Q);//P节点个数,Q边个数
96 for(int i=0;i<=P;i++)
97 {
98 ind[0][i]=NULL;
99 ind[1][i]=NULL;
100 }
101
102 ednum =0;
103 long a,b,c;
104 while(Q--)
105 {
106 //scanf("%ld%ld%ld",&a,&b,&c);
107 a = getint();
108 b = getint();
109 c = getint();
110 addEdge(a,b,c);
111 }
112 __int64 ans =0;
113 for(int i=0;i<2;i++)//分别对应于求正向图与反向图的単源最短路
114 {
115 spfa(i,1,P);
116 for(int j=1;j<=P;j++)
117 ans+=dis[j];
118 }
119
120 printf("%I64d\n",ans);
121 }
122 }
123 return0;
124 }
2 #include<string.h>
3 #include<queue>
4 #include<iostream>
5 usingnamespace std;
6 constint N =1000000+5;//顶点个数
7 struct EDGE
8 {
9 long v;
10 long price;
11 EDGE *next;
12 }edges[2][N],*ind[2][N];//使用指针实现邻接表的存储
13
14 __int64 dis[N];
15 int ednum;//记录边数
16 bool isInQueue[N];//isInQueue[i]标记i当前是否在队列中
17 void spfa(int eid,int sid,int n)//spfa求eid图中从sid出发的単源最短路径
18 {
19 queue<int>myQueue;
20 int i,j;
21 for(i=1;i<=n;i++)
22 {
23 dis[i]=-1;
24 isInQueue[i]=false;
25 }
26
27 int cur;
28 cur = sid;
29 dis[cur]=0;
30 isInQueue[cur]=true;
31 myQueue.push(cur);
32
33 while(!myQueue.empty())
34 {
35 cur = myQueue.front();//每次仅对队列中的点进行松弛操作
36 myQueue.pop();
37 isInQueue[cur]=false;
38 for(EDGE *p = ind[eid][cur];p;p=p->next)
39 {
40 __int64 temp = p->price+dis[cur];
41 if(dis[p->v]==-1||temp<dis[p->v])
42 {
43 dis[p->v]=temp;
44 if(isInQueue[p->v]==false)
45 {
46 myQueue.push(p->v);
47 isInQueue[p->v]=true;
48 }
49 }
50 }
51
52 }
53
54 }
55
56 //添加新边
57 inline void addEdge(long a,long b,long c)
58 {
59 EDGE *po,*op;
60 po =&edges[0][ednum];//正向边
61 op =&edges[1][ednum];//反向边
62 ednum++;
63
64 po->price = c;
65 po->v = b;
66 po->next = ind[0][a];
67 ind[0][a]=po;
68
69 op->price = c;
70 op->v = a;
71 op->next = ind[1][b];
72 ind[1][b]=op;
73
74 }
75
76 inline long getint() //这个getchar的输入对大数据量输入非常有用,甚至可以挽救效率不高的算法
77 {
78 long ret=0;
79 char tmp;
80 while(!isdigit(tmp=getchar()));
81 do{
82 ret=(ret<<3)+(ret<<1)+tmp-'0';
83 }while(isdigit(tmp=getchar()));
84 return ret;
85 }
86
87 int main()
88 {
89 int T;
90 while(scanf("%d",&T)!=EOF)
91 {
92 while(T--)
93 {
94 int P,Q;
95 scanf("%d%d",&P,&Q);//P节点个数,Q边个数
96 for(int i=0;i<=P;i++)
97 {
98 ind[0][i]=NULL;
99 ind[1][i]=NULL;
100 }
101
102 ednum =0;
103 long a,b,c;
104 while(Q--)
105 {
106 //scanf("%ld%ld%ld",&a,&b,&c);
107 a = getint();
108 b = getint();
109 c = getint();
110 addEdge(a,b,c);
111 }
112 __int64 ans =0;
113 for(int i=0;i<2;i++)//分别对应于求正向图与反向图的単源最短路
114 {
115 spfa(i,1,P);
116 for(int j=1;j<=P;j++)
117 ans+=dis[j];
118 }
119
120 printf("%I64d\n",ans);
121 }
122 }
123 return0;
124 }