• [NOIP2017 TG D2T2]宝藏


    题目大意:给定一个有重边,边有权值的无向图。从某一个点出发,求到达所有的点需要的最少费用,
    并且限制两点之间只有一条路径。
    费用的计算公式为:所有边的费用之和。而边$(x->y)$的费用就为:$y$到初始点的距离$ imes$边权。

    题解:记忆化搜索,$f[i][j]$表示第$i$个节点,比到这个点的最短多了$j$的方案数,在反图上跑就行了,如果一个点被访问时还在栈中,就有零环

    卡点:无(但是可以构造数据卡$SPFA$)

    C++ Code:(SFPA)

    #include <cstdio>
    #include <cstring>
    #define maxn 100010
    #define maxm 200010
    using namespace std;
    int Tim, n, m, k, P;
    bool flag;
    struct Edge {int to, nxt, w;};
    struct Graph{
    	int head[maxn], cnt;
    	Edge e[maxm];
    	void add(int a, int b, int c) {
    		e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
    	}
    } G1, G2;
    int dis[maxn], f[maxn][55];
    int q[maxn << 2], h, t;
    bool vis[maxn], s[maxn][55];
    int dfs(int x, int num) {
    	if (~f[x][num]) return f[x][num];
    	int ans = 0, v, tmp;
    	s[x][num] = true;
    	for (int i = G2.head[x]; i; i = G2.e[i].nxt) {
    		v = G2.e[i].to;
    		tmp = dis[x] - dis[v] + num - G2.e[i].w;
    		if (tmp < 0 || tmp > k) continue;
    		if (s[v][tmp]) {
    			flag = true;
    			return 0;
    		}
    		ans = (ans + dfs(v, tmp)) % P;
    		if (flag) return 0;
    	}
    	s[x][num] = false;
    	return f[x][num] = ans;
    }
    int solve(int st) {
    	memset(f, -1, sizeof f);
    	int ans = 0; flag = false;
    	f[st][st] = 1;
    	for (int i = 0; i <= k; i++) {
    		int tmp = dfs(n, i);
    		ans = (ans + tmp) % P;
    		if (flag) break;
    	}
    	if (flag) return -1;
    	else return ans;
    }
    void SPFA(int st) {
    	memset(dis, 0x3f, sizeof dis);
    	memset(vis, false, sizeof vis);
    	dis[q[h = t = 0] = st] = 0;
    	while (h <= t) {
    		int u = q[h++];
    		vis[u] = false;
    		for (int i = G1.head[u]; i; i = G1.e[i].nxt) {
    			int v = G1.e[i].to;
    			if (dis[v] > dis[u] + G1.e[i].w) {
    				dis[v] = dis[u] + G1.e[i].w;
    				if (!vis[v]) {
    					vis[v] = true;
    					q[++t] = v;
    				}
    			}
    		}
    	}
    }
    int main() {
    	scanf("%d", &Tim); 
    	while (Tim --> 0) {
    		scanf("%d%d%d%d", &n, &m, &k, &P);
    		for (int i = 0; i < m ; i++) {
    			int a, b, c;
    			scanf("%d%d%d", &a, &b, &c);
    			G1.add(a, b, c);
    			G2.add(b, a, c);
    		}
    		G1.add(0, 1, 0);
    		G2.add(1, 0, 0);
    		SPFA(0);
    		printf("%d
    ", solve(0));
    		if (Tim) {
    			G1.cnt = G2.cnt = 0;
    			memset(G1.head, 0, sizeof G1.head);
    			memset(G2.head, 0, sizeof G2.head);
    			memset(s, false, sizeof s);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    使用内部单向链表实现的一个简单堆栈
    通过反射调用内部类的隐藏方法
    动态代理生成空对象
    通过使用java.lang.reflect.Proxy实现动态代理
    简单代理模式
    暗色CSS,适用与Stylish, IE, FF, OPERA等.
    CWnd派生的控件处理MouseMove, MouseHover, MouseLeave
    _tcscpy_s的size应至少为src的长度+1(要把计算在内)
    用INET(CHttpFile)下载有重定向链接时获取最终URL的方法.
    GetDlgItem以及其他获得CWnd相关的函数要注意。。
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9454459.html
Copyright © 2020-2023  润新知