• JZOJ 1090. 【SDOI2009】晨跑


    题目

    略,luogu上有

    解析

    一眼费用流
    然而怎么建图?
    首先我们要挖掘题中的限制条件和性质

    • 一个点只能经过一次
    • 能走的天数最长
    • 满足第二条的条件下走过的路程最短

    那么显然是最小费用最大流了
    对于后两条,我们发现我们求的最大流就要对应天数,最小费用就要对应路程最短
    再联系第一条
    一个点只能经过一次,那么我们就可以把它拆开成两个点 (i_1,i_2) 连流量为 (1) 费用为 (0) 的边,表示只能流过一次
    然后就要使 (u,v) 间的连边变为 (u_2,v_1,1,w)(v_1,u_2,0,-w)
    那么源点 (S) 就是 (1) 拆成的第二个点,汇点 (T) 就是 (n_1)

    最后跑一边 (MCMF) 就好了

    (Code)

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    
    const int N = 405 , M = 4e4 + 5;
    int n , m , pre[N] , edge[N] , dis[N] , flow[N] , h[N] , vis[N] , tot = 1 , Mincost , Maxflow , S , T;
    queue<int> Q;
    
    struct node{
    	int to , nxt , w , f;
    }e[M << 1];
    
    inline void add(int u , int v , int w , int f){e[++tot] = node{v , h[u] , w , f} , h[u] = tot;}
    
    inline int spfa()
    {
    	memset(dis , 127 , sizeof dis);
    	memset(flow , 127 , sizeof flow);
    	memset(vis , 0 , sizeof vis);
    	dis[S] = 0 , vis[S] = 1 , Q.push(S) , pre[T] = -1;
    	while (!Q.empty())
    	{
    		int now = Q.front();
    		Q.pop();
    		for(register int i = h[now]; i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (dis[now] + e[i].f < dis[v] && e[i].w)
    			{
    				dis[v] = dis[now] + e[i].f , pre[v] = now , edge[v] = i , flow[v] = min(flow[now] , e[i].w);
    				if (!vis[v]) vis[v] = 1 , Q.push(v);
    			}
    		}
    		vis[now] = 0;
    	}
    	return pre[T] != -1;
    }
    
    inline void MCMF()
    {
    	while (spfa())
    	{
    		Maxflow += flow[T];
    		Mincost += dis[T] * flow[T];
    		int now = T;
    		while (now != S)
    		{
    			e[edge[now]].w -= flow[T];
    			e[edge[now] ^ 1].w += flow[T];
    			now = pre[now];
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d" , &n , &m);
    	for(register int i = 1; i <= n; i++)
    	{
    		add(i * 2 - 1 , i * 2 , 1 , 0);
    		add(i * 2 , i * 2 - 1 , 0 , 0);
    	}
    	int u , v , f;
    	for(register int i = 1; i <= m; i++)
    	{
    		scanf("%d%d%d" , &u , &v , &f);		
    		add(u * 2 , v * 2 - 1 , 1 , f) , add(v * 2 - 1 , u * 2 , 0 , -f);
    	}
    	S = 2 , T = n * 2 - 1;
    	MCMF();
    	printf("%d %d
    " , Maxflow , Mincost);
    }
    
  • 相关阅读:
    C#中如何求时间间隔?
    Ilist<T> 转换成 DataSet
    EditPlus 快捷键
    Array和ArrayList的异同点
    sql server 查询数据库中有多少个表
    jquery + Css 模式对话框
    paddingtop、margintop和top的区别
    JQuery之ContextMenu(右键菜单)
    关于TextBox的Enable与ReadOnly属性
    AjaxToollit 3.5 使用整理
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13499216.html
Copyright © 2020-2023  润新知