zoukankan      html  css  js  c++  java
  • 「JOI 2021 Final」机器人

    「JOI 2021 Final」机器人

    原问题中颜色什么时候改没有影响

    显然不能记录每条边的颜色,显然在行走过程中不会回到原先的点

    因此考虑简化状态

    从一个点出去时,走了一条边((u,v,c,w)),从(u)出发颜色为(c)的边(w)之和为(S_{u,c}),则有两种转移:

    1.走过来时的边被改变了,权值(w)

    2.改变了其他同种颜色的边,权值(S_{u,c}-w)

    对于2情况在前面修改的边,在后面不会产生贡献(否则可以直接通过这条边过去,而不需要绕路)

    可以直接转移到对应节点

    1类转移的贡献相当于下次走这种颜色时,可以少改变一条边的颜色

    即下一次转移2时,权值变为(S_{v,c}-w-w')

    可以增加一个额外权值(-w),然后对于下一个点(v)所有颜色为(c)的出边转移,这可以通过构建虚点解决

    实际上总权值就是(0)

    考虑到一种不合法的情况,即走回(u),但是这样的转移权值就是(S_{v,c}-w'ge 0)

    非法情况无影响

    最终得到的转移就是一个非负边权的最短路图,可以跑(Dijkstra)解决

    总点数(leq n+2m),总边数(leq 6m)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    
    char IO;
    int rd(){
    	int s=0;
    	while(!isdigit(IO=getchar()));
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return s;
    }
    
    const int N=5e5+10,INF=1e9+10;
    
    int n,m,k;
    struct Edge{
    	int v,c,w;
    };
    vector <Edge> G[N];
    int U[N],V[N],C[N],W[N];
    
    struct Node{
    	int u; ll d;
    	bool operator < (const Node __) const {
    		return d>__.d;
    	}
    };
    priority_queue <Node> que;
    ll dis[N],S[N];
    void Upd(int u,ll d){
    	if(dis[u]<=d) return;
    	dis[u]=d,que.push((Node){u,d});
    }
    map <int,int> st[N];
    void AddEdge(int u,int v,int c,int w){
    	if(!st[u].count(c)) {
    		st[u][c]=++k;
    		G[u].pb((Edge){k,0,0});
    	}
    	int t=st[u][c];
    	G[t].pb((Edge){v,c,w}),S[t]+=w;
    }
    
    void Dijkstra(){
    	memset(dis,63,sizeof dis);
    	dis[1]=0,que.push((Node){1,0});
    	while(!que.empty()) {
    		int u=que.top().u; ll d=que.top().d; que.pop();
    		if(dis[u]<d) continue;
    		if(u<=n) {
    			for(Edge dd:G[u]) {
    				int t=dd.v;
    				for(Edge i:G[t]) {
    					Upd(i.v,d+min((ll)i.w,S[t]-i.w));
    					Upd(st[i.v][i.c],d);
    				}
    			}
    		} else for(Edge i:G[u]) Upd(i.v,d+S[u]-i.w);
    	}
    	printf("%lld
    ",dis[n]<1e17?dis[n]:-1);
    }
    
    int main(){
    	freopen("robot.in","r",stdin),freopen("robot.out","w",stdout);
    	n=rd(),m=rd(),k=n;
    	rep(i,1,m) {
    		int u=rd(),v=rd(),c=rd(),w=rd();
    		AddEdge(u,v,c,w),AddEdge(v,u,c,w);
    	}
    	Dijkstra();
    }
    
  • 相关阅读:
    python字符串,数组操作
    python爬虫之有道在线翻译
    英雄联盟界面
    学习photoshop心得
    linux命令总结之lsof命令
    linux命令总结之netstat命令
    linux命令总结之route命令
    linux命令总结之ip命令
    linux命令总结之dig命令
    IP地址的分类——a,b,c 类是如何划分的
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14436028.html
Copyright © 2011-2022 走看看