zoukankan      html  css  js  c++  java
  • [luogu2469] 星际竞速

    题面

    ​ 巨佬一眼就能看出这是最小路径覆盖, 我这个蒟蒻还是太弱了...

    ​ 我们可以知道跳跃值为点权w[i], 两点之间距离为边权ww

    ​ 对于每个点, 在最小路径覆盖问题中, 假设每个点都是一条路径, 即每个点都由能力爆发得到, 那么最初的答案便是(ans) = (sum_{ i = 1}^{n}), 对于每一条连接u和v的边, 可以看做不使用能力爆发而从u往v走, 那么我们就减少了点v的点权, 加上了这一条边的代价, 即从(min(u, v))(max(u, v))连一条容量为1, 费用为(ww - w[v]), 那么只要每次增广找到一条费用为负的边就可以减少总时间, 即当(d[T])小于0时就可以将(ans += d[T]), 所以, 只要当此次增广无法到达T或者(d[T]) > 0时就可以return 0了.

    具体代码

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    #define N 5005
    using namespace std;
    
    int n, m, S, T, head[N], cnt = 1, p[N], vis[N], w[N];
    struct node
    {
    	int from, to, next;
    	long long flow, cost; 
    } edge[100005];
    long long a[N], d[N], ans; 
    
    inline int read()
    {
    	int x = 0, w = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
    	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    	return x * w;
    }
    
    inline void add(int u, int v, int w, int cost)
    {
    	edge[++cnt] = { u, v, head[u], w, cost }; head[u] = cnt;
    	edge[++cnt] = { v, u, head[v], 0, -cost }; head[v] = cnt; 
    }
    
    bool SPFA()
    {
    	memset(d, 0x3f, sizeof(d)); memset(a, 0x3f, sizeof(a));
    	queue<int> q; q.push(S); d[S] = 0;
    	while(!q.empty())
    	{
    		int u = q.front(); q.pop(); vis[u] = 0; 
    		for(int i = head[u]; i; i = edge[i].next)
    		{
    			int v = edge[i].to;
    			if(d[v] > d[u] + edge[i].cost && edge[i].flow > 0)
    			{
    				d[v] = d[u] + edge[i].cost; a[v] = min(a[u], edge[i].flow);
    				p[v] = i; if(!vis[v]) { vis[v] = 1; q.push(v); }
    			}
    		}
    	}
    	if(d[T] == d[0] || d[T] > 0) return 0;
    	if(d[T] < 0) ans += (d[T] * a[T]);
    	for(int i = T; i != S; i = edge[p[i]].from)
    	{
    		edge[p[i]].flow -= a[T]; edge[p[i] ^ 1].flow += a[T]; 
    	}
    	return 1; 
    }
    
    int main()
    {
    	n = read(); m = read(); S = 2 * n + 1; T = S + 1; 
    	for(int i = 1; i <= n; i++) { w[i] = read(); ans += w[i]; add(S, i, 1, 0); }
    	for(int i = 1; i <= n; i++) add(i + n, T, 1, 0);
    	for(int i = 1; i <= m; i++)
    	{
    		int u = read(), v = read(), ww = read();
    		if(u > v) swap(u, v);
    		add(u, v + n, 1, ww - w[v]); 
    	}
    	while(SPFA());
    	printf("%lld
    ", ans); 
    	return 0;
    }
    
  • 相关阅读:
    Java hello/hi的简单的网络聊天程序
    案例分析:设计模式与代码的结构特性
    网络相关的命令工具研究报告
    如何提高程序员的键盘使用效率
    分析一套源代码的代码规范和风格并讨论如何改进优化代码
    用例建模Use Case Modeling
    结合工程实践选题调研分析同类软件产品
    领域建模
    SecureCRT 连接虚拟机Linux
    用css固定div层在页面顶部和底部(兼容IE6)
  • 原文地址:https://www.cnblogs.com/ztlztl/p/10568317.html
Copyright © 2011-2022 走看看