ACM/ICPC World Finals 2013 C Surely You Congest

题目大意

给定一个图,给你n个人的起点,同时出发,不允许两个人同时通过同一条边的同一个方向,所有人必须走最短路径,问满足这种情况的最多的人数。

解答

首先先用SPFA求出最短路图,然后对每一个到终点相同距离的人拎出来做网络流,然后将每次求出的最大流求和就可以了。

附上AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>

using namespace std;

const int MAXM = 150005;
const int MAXN = 100000;
const int oo = 2147483647;

inline int getint()
{
    int ans = 0;
    char w = getchar();
    while (w < '0' || w > '9')
        w = getchar();
    while ('0' <= w && w <= '9') {
        ans = ans * 10 + w - '0';
        w = getchar();
    }
    return ans;
}

class Edge
{
    public:
        int to;
        int len;
        int next;
};

class PEdge
{
    public:
        int to;
        int from;
        int len;
        int next;
};

Edge es[MAXM];
Edge ces[MAXN];
int head[MAXN];
int h[MAXN];
int ch[MAXN];
PEdge ee[MAXM];
int person[MAXN];
int ph[MAXN];
int et = -1;
int cet = -1;
int pet = -1;
int st, th;
int fl[MAXN];
bool vis[MAXN];
int dis[MAXN];
int n, m, c;

bool cmp(int a, int b)
{
    return dis[a] < dis[b];
}

void addEdge(int u, int v)
{
    cet++;
    ces[cet].to = v;
    ces[cet].len = 1;
    ces[cet].next = ch[u];
    ch[u] = cet;
    cet++;
    ces[cet].to = u;
    ces[cet].len = 0;
    ces[cet].next = ch[v];
    ch[v] = cet;
}

void add(int u, int v, int l)
{
    pet++;
    ee[pet].to = v;
    ee[pet].from = u;
    ee[pet].len = l;
    ee[pet].next = ph[u];
    ph[u] = pet;
    pet++;
    ee[pet].to = u;
    ee[pet].from = v;
    ee[pet].len = l;
    ee[pet].next = ph[v];
    ph[v] = pet;
}

void newEdge(int u, int v)
{
    et++;
    es[et].to = v;
    es[et].len = 1;
    es[et].next = h[u];
    h[u] = et;
    et++;
    es[et].to = u;
    es[et].len = 0;
    es[et].next = h[v];
    h[v] = et;
}

bool bfs()
{
    memset(fl, 0, sizeof(fl));
    queue<int> ser;
    fl[st] = 1;
    ser.push(st);
    int root;
    bool flag = false;
    while (!ser.empty()) {
        root = ser.front();
        ser.pop();
        for (int i = h[root]; i != -1; i = es[i].next)
            if (es[i].len && !fl[es[i].to]) {
                fl[es[i].to] = fl[root] + 1;
                ser.push(es[i].to);
                if (es[i].to == th)
                    flag = true;
            }
    }
    return flag;
}

int dfs(int x, int flow)
{
    if (x == th)
        return flow;
    int cflow = flow;
    int ret;
    for (int &i = head[x]; i != -1; i = es[i].next)
        if (es[i].len && fl[es[i].to] == fl[x]+1) {
            ret = dfs(es[i].to, min(flow, es[i].len));
            es[i].len -= ret;
            es[i^1].len += ret;
            flow -= ret;
            if (!flow)
                return cflow;
        }
    return cflow-flow;
}

int dinic()
{
    int ans = 0;
    while(bfs()) {
        for (int i = 1; i <= n+2; i++)
            head[i] = h[i];
        ans += dfs(st, oo);
    }
    return ans;
}

void SPFA(int s = 1)
{
    queue<int> ser;
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++)
        dis[i] = oo;
    dis[s] = 0;
    ser.push(s);
    int root;
    vis[s] = true;
    while(!ser.empty()) {
        root = ser.front();
        ser.pop();
        for (int i = ph[root]; i != -1; i = ee[i].next) {
            if (dis[ee[i].to] > dis[root]+ee[i].len) {
                dis[ee[i].to] = dis[root]+ee[i].len;
                if (!vis[ee[i].to]) {
                    ser.push(ee[i].to);
                    vis[ee[i].to] = true;
                }
            }
        }
        vis[root] = false;
    }
}

void check()
{
    for (int i = 0; i < m*2; i++)
        if (dis[ee[i].to] == dis[ee[i].from] + ee[i].len) {
            addEdge(ee[i].to, ee[i].from);
        }
}

void readin()
{
    memset(h, -1, sizeof(h));
    memset(ch, -1, sizeof(ch));
    memset(ph, -1, sizeof(ph));
    n = getint();
    m = getint();
    c = getint();
    //scanf("%d %d %d", &n, &m, &c);
    int x, y, z;
    for (int i = 0; i < m; i++) {
        //scanf("%d %d %d", &x, &y, &z);
        x = getint();
        y = getint();
        z = getint();
        add(x, y, z);
    }
    SPFA();
    check();
    for (int i = 0; i < c; i++) {
        //scanf("%d", &x);
        person[i] = getint();
    }
    sort(person, person+c, cmp);
    th = 1;
    st = n+2;
}

void setUp()
{
    et = cet;
    for (int i = 0; i <= n+2; i++)
        h[i] = ch[i];
    for (int i = 0; i <= cet; i++)
        es[i] = ces[i];
}

void work()
{
    int ans = 0;
    int tmp = dis[person[0]];
    setUp();
    for (int i = 0; i < c; i++) {
        if (dis[person[i]] == tmp) {
            newEdge(st, person[i]);
        } else {
            ans += dinic();
            setUp();
            newEdge(st, person[i]);
            tmp = dis[person[i]];
        }
    }
    ans += dinic();
    printf("%d", ans);
}

int main()
{
    //freopen("input.in", "r", stdin);
    readin();
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值