• luogu3563 逛公园


    两遍 spfa 然后建立分层图拓扑排序 dp 一下。
    写得很差劲。效率很低。
    时间复杂度 (mathrm{O}(Tnk))
    参见这里秒懂。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    int T, n, m, k, p, cnt[2], hea[2][100005], dis[2][100005], uu, vv, ww, he[5100005], cn, dp[5100005];
    int ind[5100005], f[100005][55];
    bool vis[5100005];
    queue<int> d;
    struct Edge{
    	int too, nxt, val;
    }edge[2][200005], edg[10200005];
    void rn(int &x){
    	char ch=getchar();
    	x = 0;
    	while(ch<'0' || ch>'9')	ch = getchar();
    	while(ch>='0' && ch<='9'){
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    }
    void add_edge(int rr, int fro, int too, int val){
    	edge[rr][++cnt[rr]].nxt = hea[rr][fro];
    	edge[rr][cnt[rr]].too = too;
    	edge[rr][cnt[rr]].val = val;
    	hea[rr][fro] = cnt[rr];
    }
    void add_edg(int fro, int too){
    	edg[++cn].nxt = he[fro];
    	edg[cn].too = too;
    	he[fro] = cn;
    }
    void init(){
    	rn(n); rn(m); rn(k); rn(p);
    	memset(he, 0, sizeof(he));
    	memset(dp, 0, sizeof(dp));
    	memset(hea, 0, sizeof(hea));
    	memset(vis, 0, sizeof(vis));
    	memset(ind, 0, sizeof(ind));
    	memset(dis, 0x3f, sizeof(dis));
    	dis[0][1] = dis[1][n] = cnt[0] = cnt[1] = cn = 0;
    	dp[1] = 1;
    	for(int i=1; i<=m; i++){
    		rn(uu); rn(vv); rn(ww);
    		add_edge(0, uu, vv, ww);
    		add_edge(1, vv, uu, ww);
    	}
    	int qwq=0;
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=k; j++)
    			f[i][j] = ++qwq;
    }
    void spfa(int rr){
    	d.push(rr?n:1);
    	vis[rr?n:1] = true;
    	while(!d.empty()){
    		int x=d.front();
    		d.pop();
    		vis[x] = false;
    		for(int i=hea[rr][x]; i; i=edge[rr][i].nxt){
    			int t=edge[rr][i].too;
    			if(dis[rr][t]>dis[rr][x]+edge[rr][i].val){
    				dis[rr][t] = dis[rr][x] + edge[rr][i].val;
    				if(!vis[t]){
    					vis[t] = true;
    					d.push(t);
    				}
    			}
    		}
    	}
    }
    void build(){
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=k; j++)
    			if(dis[0][i]+dis[1][i]+j<=dis[0][n]+k)
    				vis[f[i][j]] = true;
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=k; j++)
    			if(vis[f[i][j]])
    				for(int l=hea[0][i]; l; l=edge[0][l].nxt){
    					int t=edge[0][l].too, v=j+dis[0][i]+edge[0][l].val-dis[0][t];
    					if(v<=k && f[t][v]){
    						add_edg(f[i][j], f[t][v]);
    						ind[f[t][v]]++;
    					}
    				}
    }
    void topsort(){
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=k; j++)
    			if(vis[f[i][j]] && !ind[f[i][j]])
    				d.push(f[i][j]);
    	while(!d.empty()){
    		int x=d.front();
    		d.pop();
    		for(int i=he[x]; i; i=edg[i].nxt){
    			int t=edg[i].too;
    			ind[t]--;
    			if(ind[t]==0)	d.push(t);
    			dp[t] = dp[t]+dp[x]>=p?dp[t]+dp[x]-p:dp[t]+dp[x];
    		}
    	}
    }
    int chk(){
    	for(int i=1; i<=f[n][k]; i++)
    		if(ind[i]!=0)
    			return -1;
    	int re=0;
    	for(int i=0; i<=k; i++)
    		re = re+dp[f[n][i]]>=p?re+dp[f[n][i]]-p:re+dp[f[n][i]];
    	return re;
    }
    int main(){
    	cin>>T;
    	while(T--){
    		init();
    		spfa(0);
    		spfa(1);
    		build();
    		topsort(); 
    		printf("%d
    ", chk());
    	}
    	return 0;
    }
    
  • 相关阅读:
    Visual Studio 20**自动添加头部注释信息
    开发使用混合式Winform模块
    java 下拉框级联及相关(转)
    Redhat关闭SELinux和防火墙的办法(转)
    icmp的报文,Destination Host Unreachable
    负载均衡-lvs
    深入浅出交换类排序算法(转)
    单源最短路径(dijkstra算法)php实现
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    oracle递归函数
  • 原文地址:https://www.cnblogs.com/poorpool/p/8449742.html
Copyright © 2020-2023  润新知