P2555 - 【2017杭二联考】图的有向环
Description
题目背景:
幻想乡的亡灵公主,西行寺幽幽子,在幻想乡很受欢迎,经常有妖怪来拜访她,但是幽 幽子并不喜欢被打扰,她希望从白玉楼出发,散步之后再回到白玉楼,同时路上遇到的妖怪 越少越好(有趣的是道路两边的妖怪数量并不相同,分别从两个方向经过同一条道路遇到的 妖怪数量是不同的)。当然,作为冥界的公主,她是不会重复经过同一条道路的。
问题描述:
给定一个有 n 个点 m 条无向边的图,每条无向边最多只能经过一次。
对于边(ui, vi), 从 ui 到 vi 的代价为 ai,从 vi 到 ui 的代价为 bi,其中 ai 和 bi 不一定相等。 求一个包 含 1 号点的有向环,使得环上代价之和最小。(保证图中没有重边和自环。)
Input
第一行两个个正整数 n,m,点数和边数。
接下来 m 行,每行四个正整数,ui,vi,ai,bi。
从 ui 到 vi 的代价为 ai,从 vi 到 ui 的代价为 bi 。
Output
输出一行,一个整数,如果有解输出最小代价,否则输出''-1''(不含引号)。
Sample Input
3 3
1 2 4 3
2 3 4 2
1 3 1 1
Sample Output
6
Hint
数据范围:
对于前 15% 的数据,3 <= n <= 20, 3 <= m <= 20
对于前 30% 的数据,3 <= n <= 150, 3 <= m <= 2500
对于前 70% 的数据,3 <= n <= 5000, 3 <= m <= 10^4
对于 100% 的数据, 3 <= n <= 30000 , 3 <= m <= 10^5 , 1<=ui, vi <= n,1 <= ai, bi <= 10^4。
保证图中没有重边,即不存在 i <> j,使得 ui = uj,vi = vj。
保证图中没有自环,即 ui <> vi。
Source
图论,最短路
枚举与一号点相连的每一条边,再跑SPFA,min(枚举的边的长度+dis[1])即为答案,但是要注意剪枝和优化.
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<algorithm> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 #define RG register 12 #define IL inline 13 #define pi acos(-1.0) 14 #define ll long long 15 using namespace std; 16 struct edge{ 17 int first,nxt,to,w; 18 }; 19 edge a[200050]; 20 int n,m,num,minn; 21 int f[200050],dis[100050]; 22 bool pan[100050]; 23 void add(int l,int r,int w){ 24 a[++num].to=r; 25 a[num].w=w; 26 a[num].nxt=a[l].first; 27 a[l].first=num; 28 } 29 inline void spfa(int S,int w){ 30 for(RG int i=1;i<=n;i++) dis[i]=999999999; 31 memset(pan,true,sizeof(pan)); 32 queue <int> s; 33 s.push(S); 34 dis[S]=w; 35 while(!s.empty()){ 36 int u=s.front(); 37 s.pop(); 38 pan[u]=true; 39 if(dis[u]>=minn) continue; 40 if(u==1) {minn=min(minn,dis[u]);continue;} 41 for(int i=a[u].first;i;i=a[i].nxt){ 42 if(f[i]) continue; 43 int v=a[i].to; 44 if(dis[u]+a[i].w<dis[v]){ 45 dis[v]=dis[u]+a[i].w; 46 if(pan[v]){ 47 pan[v]=false; 48 s.push(v); 49 } 50 } 51 } 52 } 53 } 54 int main() { 55 scanf("%d%d",&n,&m); 56 for(int i=1;i<=m;i++){ 57 int u,v,a,b; 58 scanf("%d%d%d%d",&u,&v,&a,&b); 59 add(u,v,a),add(v,u,b); 60 } 61 minn=999999999; 62 for(int i=a[1].first;i;i=a[i].nxt){ 63 f[i]=1; 64 if(i%2==0) f[i-1]=1; 65 else f[i+1]=1; 66 spfa(a[i].to,a[i].w); 67 f[i]=0; 68 if(i%2==0) f[i-1]=0; 69 else f[i+1]=0; 70 } 71 if(minn==999999999) printf("-1"); 72 else printf("%d",minn); 73 return 0; 74 }