• [题解] [JSOI2014] 支线剧情


    题面

    题解

    很经典的上下界网络流模板题

    每条边下界为 1 , 上界为 INF , 然后跑一遍最小费用可行流即可

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    const int N = 305;
    const int M = 200005; 
    typedef long long ll;
    const int INF = 0x3f3f3f3f; 
    using namespace std;
    
    int n, S, T, s, t, k[N], c[N][N], b[N][N], d[N], head[N], cnt = 1, p[N];
    ll ans, dis[N], a[N];
    struct edge { int to, nxt; ll flow, cost; } e[M << 1]; 
    bool vis[N];
    queue<int> q; 
    
    template < typename T >
    inline T read()
    {
        T 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 adde(int u, int v, int w, int c)
    {
        e[++cnt] = (edge) { v, head[u], w, c }, head[u] = cnt;
        e[++cnt] = (edge) { u, head[v], 0, -c }, head[v] = cnt; 
    }
    
    bool SPFA()
    {
        memset(dis, 0x3f, sizeof(dis)), memset(a, 0x3f, sizeof(a));
        dis[s] = 0, q.push(s), vis[s] = 0; 
        while(!q.empty())
        {
    	int u = q.front(); q.pop(); vis[u] = 0;
    	for(int v, i = head[u]; i; i = e[i].nxt)
    	{
    	    v = e[i].to;
    	    if(dis[v] > dis[u] + e[i].cost && e[i].flow)
    	    {
    		dis[v] = dis[u] + e[i].cost, a[v] = min(a[u], e[i].flow);
    		p[v] = i; if(!vis[v]) vis[v] = 1, q.push(v); 
    	    }
    	}
        }
        if(dis[t] == dis[0]) return 0;
        ans += a[t] * dis[t];
        for(int i = t; i != s; i = e[p[i] ^ 1].to)
    	e[p[i]].flow -= a[t], e[p[i] ^ 1].flow += a[t];
        return 1; 
    }
    
    int main()
    {
        n = read <int> (), S = n + 1, T = S + 1, s = T + 1, t = s + 1; 
        for(int i = 1; i <= n; i++)
        {
    	k[i] = read <int> ();
    	for(int j = 1; j <= k[i]; j++)
    	{
    	    c[i][j] = read <int> (), b[i][j] = read <int> ();
    	    d[c[i][j]]++, d[i]--, ans += b[i][j];
    	    adde(i, c[i][j], INF, b[i][j]); 
    	}
        }
        adde(S, 1, INF, 0); 
        for(int i = 1; i <= n; i++)
    	adde(i, T, INF, 0);
        adde(T, S, INF, 0); 
        for(int i = 1; i <= n; i++)
    	if(d[i] < 0) adde(i, t, -d[i], 0);
    	else if(d[i] > 0) adde(s, i, d[i], 0); 
        while(SPFA());
        printf("%lld
    ", ans); 
        return 0; 
    }
    
  • 相关阅读:
    bootstrap入门基础
    java遇见的问题分析
    蓝桥杯练习
    win7 在文件夹上右键后 以管理员启动命令窗口
    渲染10万条数据的性能问题
    闲聊一下百度的Unit
    利用c# 多屏显示
    学习Xposed --记WX功能分析的过程
    从零开始打jar包--补充
    修改windows7 的管理员密码
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12296575.html
Copyright © 2020-2023  润新知