zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Linux编程 22 shell编程(输出和输入重定向,管道,数学运算命令,退出脚本状态码)
    mysql 开发进阶篇系列 46 物理备份与恢复( xtrabackup的 选项说明,增加备份用户,完全备份案例)
    mysql 开发进阶篇系列 45 物理备份与恢复(xtrabackup 安装,用户权限,配置)
    mysql 开发进阶篇系列 44 物理备份与恢复( 热备份xtrabackup 工具介绍)
    Linux编程 21 shell编程(环境变量,用户变量,命令替换)
    Linux编程 20 shell编程(shell脚本创建,echo显示信息)
    mysql 开发进阶篇系列 43 逻辑备份与恢复(mysqldump 的基于时间和位置的不完全恢复)
    Linux编程 19 编辑器(vim 用法)
    (网页)angularjs中的interval定时执行功能(转)
    (网页)在SQL Server中为什么不建议使用Not In子查询(转)
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14179676.html
Copyright © 2011-2022 走看看