bzoj 4398: 福慧雙修(最短路建模/構造)
阿新 • • 發佈:2018-12-18
簡述題意: 給定一個有向圖,對於連線同兩個點的邊算作同一條,問不經過重複邊的最小正權環。
保證沒有重邊(這個是指有向的),沒有自環。
演算法:最短路+構造
難度:NOIP+
題解:
請見黃學長部落格,黃學長描述的再清楚不過了!!!
程式碼如下(仿hzwer):
#include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <queue> #define ll long long #define N 100005 using namespace std; struct node { int next; int to; int val; }edg[N<<1]; int hea[N],cnt=1; void init() { memset(hea,-1,sizeof(hea)); cnt=1; } void add(int u,int v,int w) { edg[cnt].next=hea[u]; edg[cnt].to=v; edg[cnt].val=w; hea[u]=cnt++; } struct no { int d; int po; }; bool operator < (no x,no y) { return x.d>y.d; } int dis[N],vis[N]; int p[N]; int n,m; void dij(int rt) { memset(dis,0x3f3f3f3f,sizeof(dis)); priority_queue<no>Q; no temp; temp.po=rt; temp.d=0; dis[rt]=0; Q.push(temp); while(!Q.empty()) { temp=Q.top(); Q.pop(); int u=temp.po; if(vis[u]) continue; vis[u]=1; for(int i = hea[u];i != -1;i=edg[i].next) { int to=edg[i].to; if(vis[to]) continue; if(dis[to]>dis[u]+edg[i].val) { if(u==1) p[to]=to; else p[to]=p[u]; dis[to]=dis[u]+edg[i].val; no point; point.po=to; point.d=dis[to]; Q.push(point); } } } } int a[N<<1],b[N<<1],c[N<<1]; int tot,T; void ins(int x,int y,int w) { a[++tot]=x,b[tot]=y,c[tot]=w; } void rb() { for(int x = 1;x <= n;x++) { for(int i = hea[x];i != -1;i = edg[i].next) { if(edg[i].to==1) { if(p[x]!=x)ins(1,T,dis[x]+edg[i].val); else ins(x,T,edg[i].val); } if(x==1) { if(p[edg[i].to]!=edg[i].to) ins(1,edg[i].to,edg[i].val); } if(edg[i].to!=1&&x!=1) { if(p[x]!=p[edg[i].to])ins(1,edg[i].to,dis[x]+edg[i].val); else ins(x,edg[i].to,edg[i].val); } } } init(); memset(vis,0,sizeof(vis)); for(int i = 1;i <= tot;i++) add(a[i],b[i],c[i]); } int main() { scanf("%d%d",&n,&m); init(); for(int i = 1;i <= m;i++) { int x,y,w,ww; scanf("%d%d%d%d",&x,&y,&w,&ww); add(x,y,w),add(y,x,ww); } dij(1); T=n+1; rb(); dij(1); if(dis[T]==0x3f3f3f3f) puts("-1"); else printf("%d\n",dis[T]); return 0 ; }