[题解] [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\n", ans); 
    return 0; 
}
posted @ 2020-02-11 20:21  ztlztl  阅读(100)  评论(0编辑  收藏  举报