• CodeForces


    ( ext{Bi Bi Time!})

    “好家伙。”

    ( ext{Description})

    传送门

    ( ext{Solution})

    首先可以把不定边都赋值为 (1) 跑一遍最短路,如果这样最短路大于 (L) 或不是通路就无解。

    法一​

    微调法。

    考虑对任意一条不定边 (+1),每次最短路最多只会增加 (1),那么我们这样微调如果能取过 (L) 就一定能取到 (L)

    如何微调?我们将不定边编一个序号,按这个顺序一次给每条不定边 (+1)(相当于一个优先级,但注意每次只能 (+1))。二分微调总次数,显然对于每条边就能求出这条边的增量,我们跑一遍最短路判定是否合法就行了。

    不过难道不会出现序号后面需要 (+1),前面的那个不能 (+1) 的情况吗?

    其实就是害怕改变最短路大小或最短路路径。

    对于大小很好解决,让前面那个 (+1),最后一个改变最短路大小的不 (+1) 就可以了。

    对于路径呢?如果改变了路径,就说明有更好的路径,这个路径和“前面的那个”的最短路路径等效,也不会有问题。

    时间复杂度 (mathcal O(mlog n log (m imes L)))

    这里贴一份知名博主的代码吧:

    #include <cstdio>
    #include <cstring>
    #include <iostream> 
    #include <queue>
    using namespace std;
    const int M = 100005;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,L,cnt,s,t,tot,f[M],a[M],b[M],c[M],tag[M],dis[M];
    struct edge
    {
    	int v,c,next;
    }e[2*M];
    struct node
    {
    	int u,c;
    	bool operator < (const node &b) const
    	{
    		return c>b.c;
    	}
    };
    int dij()
    {
    	priority_queue<node> q;
    	q.push(node{s,0});
    	memset(dis,0x3f,sizeof dis);
    	dis[s]=0;
    	while(!q.empty())
    	{
    		node t=q.top();q.pop();
    		if(dis[t.u]<t.c) continue;
    		for(int i=f[t.u];i;i=e[i].next)
    		{
    			int v=e[i].v,c=e[i].c;
    			if(dis[v]>dis[t.u]+c)
    			{
    				dis[v]=dis[t.u]+c;
    				q.push(node{v,dis[v]});
    			}
    		}
    	}
    	return dis[t];
    }
    int check(int x)//返回序列长度是x的最短路长度 
    {
    	tot=0;
    	memset(f,0,sizeof f);
    	for(int i=1;i<=m;i++)
    	{
    		int ct=c[i];
    		if(tag[i]) ct+=x/cnt+(x%cnt>=tag[i]);
    		e[++tot]=edge{a[i],ct,f[b[i]]},f[b[i]]=tot;
    		e[++tot]=edge{b[i],ct,f[a[i]]},f[a[i]]=tot;
    	}
    	return dij();
    }
    void print(int x)
    {
    	puts("YES");
    	for(int i=1;i<=m;i++)
    	{
    		int ct=c[i];
    		if(tag[i]) ct+=x/cnt+(x%cnt>=tag[i]);
    		printf("%lld %lld %lld
    ",a[i]-1,b[i]-1,ct);
    	}
    }
    void dich(int l,int r)
    {
    	if(l>r) return;
    	int mid=(l+r)>>1,t=check(mid);
    	if(t==L)
    	{
    		print(mid);
    		exit(0);
    	}
    	if(t>L) dich(l,mid-1);
    	else dich(mid+1,r);
    }
    signed main()
    {
    	n=read();m=read();L=read();s=read()+1;t=read()+1;
    	for(int i=1;i<=m;i++)
    	{
    		a[i]=read()+1;b[i]=read()+1;c[i]=read();
    		if(c[i]==0) tag[i]=++cnt,c[i]=1;
    	}
    	dich(0,L*m);
    	puts("NO");
    }
    

    法二

    注意第一次的最短路(文首)从 (t) 开始,设这次算出的最短路数组为 (dis)

    第二次从 (s) 开始做最短路,设这次算出的最短路数组为 (d)。遇到不定边 ((u,v)) 就把这条边赋值为 (w=max{1,L-dis_v-d_u}),显然如果赋值的边权大于 (w) 会使这条路径直接废掉,因为前面的已尘埃落定,后面的又已经是能做到最短的了。

    那么如果这条边成功更新了 (d_v),我们就万事大吉。如果不行就说明已经算出的到 (v) 的路径有更短的,显然将边权赋值小于 (w) 也就不会更优了,还不如更短的那个。

    时间复杂度 (mathcal O(mlog n))

    ( ext{Code})

    #include <cstdio>
    
    #define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
    #define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
    #define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
    template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
    template <class T> inline T fab(const T x) {return x>0?x:-x;}
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
    template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}
    
    #include <queue>
    using namespace std;
    #define int long long
    typedef long long ll;
    typedef pair <ll,int> Pair;
    
    const int maxn=1005,maxm=10005;
    const ll inf=(1ll<<50);
    
    int n,m,L,s,t,l[maxm],r[maxm],ans[maxm];
    ll dis[maxn],d[maxn];
    int head[maxn],nxt[maxm<<1],to[maxm<<1],val[maxm<<1],id[maxm<<1],cnt;
    priority_queue <Pair> q;
    bool vis[maxn];
    
    void addEdge(int u,int v,int w,int ID) {
    	nxt[++cnt]=head[u],to[cnt]=v,val[cnt]=w,head[u]=cnt,id[cnt]=ID;
    	nxt[++cnt]=head[v],to[cnt]=u,val[cnt]=w,head[v]=cnt,id[cnt]=ID;
    }
    
    void Dijkstra1() {
    	rep(i,1,n) dis[i]=inf;
    	q.push(make_pair(0,t)); dis[t]=0;
    	while(!q.empty()) {
    		Pair t=q.top(); q.pop();
    		int u=t.second;
    		if(-t.first!=dis[u]||vis[u]) continue;
    		vis[u]=1;
    		erep(i,u) {
    			if(vis[v]) continue;
    			int w=val[i]?val[i]:1;
    			if(dis[v]>dis[u]+w) {
    				dis[v]=dis[u]+w;
    				q.push(make_pair(-dis[v],v));
    			}
    		}
    	}
    }
    
    void Dijkstra2() {
    	rep(i,1,n) d[i]=inf,vis[i]=0;
    	q.push(make_pair(0,s)); d[s]=0;
    	while(!q.empty()) {
    		Pair t=q.top(); q.pop();
    		int u=t.second;
    		if(d[u]!=-t.first||vis[u]) continue;
    		vis[u]=1;
    		erep(i,u) {
    			if(vis[v]) continue;
    			int w=val[i];
    			if(!w) ans[id[i]]=w=Max(1ll,0ll+L-d[u]-dis[v]);
    			if(d[v]>d[u]+w) {
    				d[v]=d[u]+w;
    				q.push(make_pair(-d[v],v));
    			}
    		}
    	}
    }
    
    signed main() {
    	int x,y,z;
    	n=read(9),m=read(9),L=read(9),s=read(9)+1,t=read(9)+1;
    	rep(i,1,m) {
    		x=read(9)+1,y=read(9)+1,z=read(9);
    		l[i]=x-1,r[i]=y-1,ans[i]=z;
    		addEdge(x,y,z,i);
    	}
    	Dijkstra1(); Dijkstra2();
    	if(d[t]^L) return puts("NO"),0;
    	puts("YES");
    	rep(i,1,m) printf("%lld %lld %lld
    ",l[i],r[i],ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    高斯金字塔、拉普拉斯金字塔
    边缘检测:Canny算子,Sobel算子,Laplace算子
    数据结构-排序
    数据结构-查找
    数据结构-图
    数据结构-树
    数据结构-串
    数据结构-栈和队列
    数据结构-链表
    数据结构-线性表存储
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14179676.html
Copyright © 2020-2023  润新知