1. 程式人生 > >bzoj 4398: 福慧雙修(最短路建模/構造)

bzoj 4398: 福慧雙修(最短路建模/構造)

簡述題意: 給定一個有向圖,對於連線同兩個點的邊算作同一條,問不經過重複邊的最小正權環。

                     保證沒有重邊(這個是指有向的),沒有自環。

演算法:最短路+構造

難度: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 ;
}